Refactor third-party type imports and update related components

- Changed import path for ThirdParty type in TypeThirdParty.vue and updated its usage.
- Refactored PersonText.vue to import Person and AltName types from ChillPersonAssets.
- Updated types.ts in ChillThirdPartyBundle to include a new 'type' field in the Thirdparty interface.
- Modified TicketBundle types to accommodate Thirdparty type in CallerState.
- Adjusted AddresseeSelectorComponent.vue to use 'thirdparty' instead of 'third_party'.
- Refined BannerComponent.vue to improve readability and maintainability.
- Updated CallerSelectorComponent.vue to reflect changes in entity types.
- Enhanced TicketHistoryListComponent.vue to handle both Person and Thirdparty types.
- Refactored TicketHistoryPersonComponent.vue to accept both Person and Thirdparty entities.
This commit is contained in:
borisw 2025-07-07 16:35:31 +02:00
parent dbf363a9e8
commit 6eeb717b1a
14 changed files with 1333 additions and 1397 deletions

View File

@ -1,287 +1,269 @@
import { GenericDoc } from "ChillDocStoreAssets/types/generic_doc"; import { GenericDoc } from "ChillDocStoreAssets/types/generic_doc";
export interface DateTime { export interface DateTime {
datetime: string; datetime: string;
datetime8601: string; datetime8601: string;
} }
export interface Civility { export interface Civility {
id: number; id: number;
// TODO // TODO
} }
export interface Household { export interface Household {
type: "household"; type: "household";
id: number; id: number;
} }
export interface Job { export interface Job {
id: number; id: number;
type: "user_job"; type: "user_job";
label: { label: {
fr: string; // could have other key. How to do that in ts ? fr: string; // could have other key. How to do that in ts ?
}; };
} }
export interface Center { export interface Center {
id: number; id: number;
type: "center"; type: "center";
name: string; name: string;
} }
export interface Scope { export interface Scope {
id: number; id: number;
type: "scope"; type: "scope";
name: { name: {
fr: string; fr: string;
}; };
} }
export interface ResultItem<T> { export interface ResultItem<T> {
result: T; result: T;
relevance: number; relevance: number;
} }
export interface User { export interface User {
type: "user"; type: "user";
id: number; id: number;
username: string; username: string;
text: string; text: string;
text_without_absence: string; text_without_absence: string;
email: string; email: string;
user_job: Job; user_job: Job;
label: string; label: string;
// todo: mainCenter; mainJob; etc.. // todo: mainCenter; mainJob; etc..
}
export interface ThirdParty {
type: "thirdparty";
id: number;
text: string;
firstname: string;
name: string;
email: string;
telephone: string;
telephone2: string;
address: {
address_id: number;
text: string;
postcode: {
name: string;
};
id: number;
};
} }
export interface UserGroup { export interface UserGroup {
type: "user_group"; type: "user_group";
id: number; id: number;
label: TranslatableString; label: TranslatableString;
backgroundColor: string; backgroundColor: string;
foregroundColor: string; foregroundColor: string;
excludeKey: string; excludeKey: string;
text: string; text: string;
} }
export type UserGroupOrUser = User | UserGroup; export type UserGroupOrUser = User | UserGroup;
export interface UserAssociatedInterface { export interface UserAssociatedInterface {
type: "user"; type: "user";
id: number; id: number;
} }
export type TranslatableString = Record<string, string>; export type TranslatableString = Record<string, string>;
export interface Postcode { export interface Postcode {
id: number; id: number;
name: string; name: string;
code: string; code: string;
center: Point; center: Point;
} }
export interface Point { export interface Point {
type: "Point"; type: "Point";
coordinates: [lat: number, lon: number]; coordinates: [lat: number, lon: number];
} }
export interface Country { export interface Country {
id: number; id: number;
name: TranslatableString; name: TranslatableString;
code: string; code: string;
} }
export type AddressRefStatus = "match" | "to_review" | "reviewed"; export type AddressRefStatus = "match" | "to_review" | "reviewed";
export interface Address { export interface Address {
type: "address"; type: "address";
address_id: number; address_id: number;
text: string; text: string;
street: string; street: string;
streetNumber: string; streetNumber: string;
postcode: Postcode; postcode: Postcode;
country: Country; country: Country;
floor: string | null; floor: string | null;
corridor: string | null; corridor: string | null;
steps: string | null; steps: string | null;
flat: string | null; flat: string | null;
buildingName: string | null; buildingName: string | null;
distribution: string | null; distribution: string | null;
extra: string | null; extra: string | null;
confidential: boolean; confidential: boolean;
lines: string[]; lines: string[];
addressReference: AddressReference | null; addressReference: AddressReference | null;
validFrom: DateTime; validFrom: DateTime;
validTo: DateTime | null; validTo: DateTime | null;
point: Point | null; point: Point | null;
refStatus: AddressRefStatus; refStatus: AddressRefStatus;
isNoAddress: boolean; isNoAddress: boolean;
} }
export interface AddressWithPoint extends Address { export interface AddressWithPoint extends Address {
point: Point; point: Point;
} }
export interface AddressReference { export interface AddressReference {
id: number; id: number;
createdAt: DateTime | null; createdAt: DateTime | null;
deletedAt: DateTime | null; deletedAt: DateTime | null;
municipalityCode: string; municipalityCode: string;
point: Point; point: Point;
postcode: Postcode; postcode: Postcode;
refId: string; refId: string;
source: string; source: string;
street: string; street: string;
streetNumber: string; streetNumber: string;
updatedAt: DateTime | null; updatedAt: DateTime | null;
} }
export interface SimpleGeographicalUnit { export interface SimpleGeographicalUnit {
id: number; id: number;
layerId: number; layerId: number;
unitName: string; unitName: string;
unitRefId: string; unitRefId: string;
} }
export interface GeographicalUnitLayer { export interface GeographicalUnitLayer {
id: number; id: number;
name: TranslatableString; name: TranslatableString;
refId: string; refId: string;
} }
export interface Location { export interface Location {
type: "location"; type: "location";
id: number; id: number;
active: boolean; active: boolean;
address: Address | null; address: Address | null;
availableForUsers: boolean; availableForUsers: boolean;
createdAt: DateTime | null; createdAt: DateTime | null;
createdBy: User | null; createdBy: User | null;
updatedAt: DateTime | null; updatedAt: DateTime | null;
updatedBy: User | null; updatedBy: User | null;
email: string | null; email: string | null;
name: string; name: string;
phonenumber1: string | null; phonenumber1: string | null;
phonenumber2: string | null; phonenumber2: string | null;
locationType: LocationType; locationType: LocationType;
} }
export interface LocationAssociated { export interface LocationAssociated {
type: "location"; type: "location";
id: number; id: number;
} }
export interface LocationType { export interface LocationType {
type: "location-type"; type: "location-type";
id: number; id: number;
active: boolean; active: boolean;
addressRequired: "optional" | "required"; addressRequired: "optional" | "required";
availableForUsers: boolean; availableForUsers: boolean;
editableByUsers: boolean; editableByUsers: boolean;
contactData: "optional" | "required"; contactData: "optional" | "required";
title: TranslatableString; title: TranslatableString;
} }
export interface NewsItemType { export interface NewsItemType {
id: number; id: number;
title: string; title: string;
content: string; content: string;
startDate: DateTime; startDate: DateTime;
endDate: DateTime | null; endDate: DateTime | null;
} }
export interface WorkflowAvailable { export interface WorkflowAvailable {
name: string; name: string;
text: string; text: string;
} }
export interface WorkflowAttachment { export interface WorkflowAttachment {
id: number; id: number;
relatedGenericDocKey: string; relatedGenericDocKey: string;
relatedGenericDocIdentifiers: object; relatedGenericDocIdentifiers: object;
createdAt: DateTime | null; createdAt: DateTime | null;
createdBy: User | null; createdBy: User | null;
updatedAt: DateTime | null; updatedAt: DateTime | null;
updatedBy: User | null; updatedBy: User | null;
genericDoc: null | GenericDoc; genericDoc: null | GenericDoc;
} }
export interface PrivateCommentEmbeddable { export interface PrivateCommentEmbeddable {
comments: Record<number, string>; comments: Record<number, string>;
} }
// API Exception types // API Exception types
export interface TransportExceptionInterface { export interface TransportExceptionInterface {
name: string; name: string;
} }
export interface ValidationExceptionInterface export interface ValidationExceptionInterface
extends TransportExceptionInterface { extends TransportExceptionInterface {
name: "ValidationException"; name: "ValidationException";
error: object; error: object;
violations: string[]; violations: string[];
titles: string[]; titles: string[];
propertyPaths: string[]; propertyPaths: string[];
} }
export interface AccessExceptionInterface extends TransportExceptionInterface { export interface AccessExceptionInterface extends TransportExceptionInterface {
name: "AccessException"; name: "AccessException";
violations: string[]; violations: string[];
} }
export interface NotFoundExceptionInterface export interface NotFoundExceptionInterface
extends TransportExceptionInterface { extends TransportExceptionInterface {
name: "NotFoundException"; name: "NotFoundException";
} }
export interface ServerExceptionInterface extends TransportExceptionInterface { export interface ServerExceptionInterface extends TransportExceptionInterface {
name: "ServerException"; name: "ServerException";
message: string; message: string;
code: number; code: number;
body: string; body: string;
} }
export interface ConflictHttpExceptionInterface export interface ConflictHttpExceptionInterface
extends TransportExceptionInterface { extends TransportExceptionInterface {
name: "ConflictHttpException"; name: "ConflictHttpException";
violations: string[]; violations: string[];
} }
export type ApiException = export type ApiException =
| ValidationExceptionInterface | ValidationExceptionInterface
| AccessExceptionInterface | AccessExceptionInterface
| NotFoundExceptionInterface | NotFoundExceptionInterface
| ServerExceptionInterface | ServerExceptionInterface
| ConflictHttpExceptionInterface; | ConflictHttpExceptionInterface;
export interface Modal { export interface Modal {
showModal: boolean; showModal: boolean;
modalDialogClass: string; modalDialogClass: string;
} }
export interface Selected { export interface Selected {
result: UserGroupOrUser; result: UserGroupOrUser;
} }
export interface addNewEntities { export interface addNewEntities {
selected: Selected[]; selected: Selected[];
modal: Modal; modal: Modal;
} }

View File

@ -1,97 +1,97 @@
<template> <template>
<a v-if="isDisplayBadge" @click="openModal"> <a v-if="isDisplayBadge" @click="openModal">
<span class="chill-entity" :class="badgeType"> <span class="chill-entity" :class="badgeType">
{{ buttonText }}<span v-if="isDead"> ()</span> {{ buttonText }}<span v-if="isDead"> ()</span>
</span> </span>
</a> </a>
<a <a
v-else v-else
class="btn btn-sm" class="btn btn-sm"
target="_blank" target="_blank"
:class="classAction" :class="classAction"
:title="trans(titleAction)" :title="trans(titleAction)"
@click="openModal" @click="openModal"
>
{{ buttonText }}<span v-if="isDead"> ()</span>
</a>
<teleport to="body">
<modal
v-if="modal.showModal"
:modal-dialog-class="modal.modalDialogClass"
@close="modal.showModal = false"
> >
{{ buttonText }}<span v-if="isDead"> ()</span> <template #header>
</a> <h3 v-if="parent" class="modal-title">
{{ trans(titleModal, { q: parent.text }) }}
</h3>
<h3 v-else class="modal-title">
{{ trans(titleModal) }}
</h3>
</template>
<teleport to="body"> <template #body v-if="type === 'person'">
<modal <on-the-fly-person
v-if="modal.showModal" :id="id"
:modal-dialog-class="modal.modalDialogClass" :type="type"
@close="modal.showModal = false" :action="action"
> ref="castPerson"
<template #header> />
<h3 v-if="parent" class="modal-title"> <div v-if="hasResourceComment">
{{ trans(titleModal, { q: parent.text }) }} <h3>{{ trans(ONTHEFLY_RESOURCE_COMMENT_TITLE) }}</h3>
</h3> <blockquote class="chill-user-quote">
<h3 v-else class="modal-title"> {{ parent.comment }}
{{ trans(titleModal) }} </blockquote>
</h3> </div>
</template> </template>
<template #body v-if="type === 'person'"> <template #body v-else-if="type === 'thirdparty'">
<on-the-fly-person <on-the-fly-thirdparty
:id="id" :id="id"
:type="type" :type="type"
:action="action" :action="action"
ref="castPerson" ref="castThirdparty"
/> />
<div v-if="hasResourceComment"> <div v-if="hasResourceComment">
<h3>{{ trans(ONTHEFLY_RESOURCE_COMMENT_TITLE) }}</h3> <h3>{{ trans(ONTHEFLY_RESOURCE_COMMENT_TITLE) }}</h3>
<blockquote class="chill-user-quote"> <blockquote class="chill-user-quote">
{{ parent.comment }} {{ parent.comment }}
</blockquote> </blockquote>
</div> </div>
</template> </template>
<template #body v-else-if="type === 'thirdparty'"> <template #body v-else-if="parent">
<on-the-fly-thirdparty <on-the-fly-thirdparty
:id="id" :parent="parent"
:type="type" :action="action"
:action="action" type="thirdparty"
ref="castThirdparty" ref="castThirdparty"
/> />
<div v-if="hasResourceComment"> </template>
<h3>{{ trans(ONTHEFLY_RESOURCE_COMMENT_TITLE) }}</h3>
<blockquote class="chill-user-quote">
{{ parent.comment }}
</blockquote>
</div>
</template>
<template #body v-else-if="parent"> <template #body v-else>
<on-the-fly-thirdparty <on-the-fly-create
:parent="parent" :action="action"
:action="action" :allowed-types="allowedTypes"
type="thirdparty" :query="query"
ref="castThirdparty" ref="castNew"
/> />
</template> </template>
<template #body v-else> <template #footer>
<on-the-fly-create <a
:action="action" v-if="action === 'show'"
:allowed-types="allowedTypes" :href="buildLocation(id, type)"
:query="query" :title="trans(titleMessage)"
ref="castNew" class="btn btn-show"
/> >{{ trans(buttonMessage) }}
</template> </a>
<a v-else class="btn btn-save" @click="saveAction">
<template #footer> {{ trans(ACTION_SAVE) }}
<a </a>
v-if="action === 'show'" </template>
:href="buildLocation(id, type)" </modal>
:title="trans(titleMessage)" </teleport>
class="btn btn-show"
>{{ trans(buttonMessage) }}
</a>
<a v-else class="btn btn-save" @click="saveAction">
{{ trans(ACTION_SAVE) }}
</a>
</template>
</modal>
</teleport>
</template> </template>
<script setup> <script setup>
import { ref, computed, defineEmits, defineProps } from "vue"; import { ref, computed, defineEmits, defineProps } from "vue";
@ -100,45 +100,45 @@ import OnTheFlyCreate from "./Create.vue";
import OnTheFlyPerson from "ChillPersonAssets/vuejs/_components/OnTheFly/Person.vue"; import OnTheFlyPerson from "ChillPersonAssets/vuejs/_components/OnTheFly/Person.vue";
import OnTheFlyThirdparty from "ChillThirdPartyAssets/vuejs/_components/OnTheFly/ThirdParty.vue"; import OnTheFlyThirdparty from "ChillThirdPartyAssets/vuejs/_components/OnTheFly/ThirdParty.vue";
import { import {
trans, trans,
ACTION_SHOW, ACTION_SHOW,
ACTION_EDIT, ACTION_EDIT,
ACTION_CREATE, ACTION_CREATE,
ACTION_ADDCONTACT, ACTION_ADDCONTACT,
ONTHEFLY_CREATE_TITLE_DEFAULT, ONTHEFLY_CREATE_TITLE_DEFAULT,
ONTHEFLY_CREATE_TITLE_PERSON, ONTHEFLY_CREATE_TITLE_PERSON,
ONTHEFLY_CREATE_TITLE_THIRDPARTY, ONTHEFLY_CREATE_TITLE_THIRDPARTY,
ONTHEFLY_SHOW_PERSON, ONTHEFLY_SHOW_PERSON,
ONTHEFLY_SHOW_THIRDPARTY, ONTHEFLY_SHOW_THIRDPARTY,
ONTHEFLY_EDIT_PERSON, ONTHEFLY_EDIT_PERSON,
ONTHEFLY_EDIT_THIRDPARTY, ONTHEFLY_EDIT_THIRDPARTY,
ONTHEFLY_ADDCONTACT_TITLE, ONTHEFLY_ADDCONTACT_TITLE,
ACTION_REDIRECT_PERSON, ACTION_REDIRECT_PERSON,
ACTION_REDIRECT_THIRDPARTY, ACTION_REDIRECT_THIRDPARTY,
ONTHEFLY_SHOW_FILE_PERSON, ONTHEFLY_SHOW_FILE_PERSON,
ONTHEFLY_SHOW_FILE_THIRDPARTY, ONTHEFLY_SHOW_FILE_THIRDPARTY,
ONTHEFLY_SHOW_FILE_DEFAULT, ONTHEFLY_SHOW_FILE_DEFAULT,
ONTHEFLY_RESOURCE_COMMENT_TITLE, ONTHEFLY_RESOURCE_COMMENT_TITLE,
ACTION_SAVE, ACTION_SAVE,
} from "translator"; } from "translator";
const props = defineProps({ const props = defineProps({
type: String, type: String,
id: [String, Number], id: [String, Number],
action: String, action: String,
buttonText: String, buttonText: String,
displayBadge: Boolean, displayBadge: Boolean,
isDead: Boolean, isDead: Boolean,
parent: Object, parent: Object,
allowedTypes: Array, allowedTypes: Array,
query: String, query: String,
}); });
const emit = defineEmits(["saveFormOnTheFly"]); const emit = defineEmits(["saveFormOnTheFly"]);
const modal = ref({ const modal = ref({
showModal: false, showModal: false,
modalDialogClass: "modal-dialog-scrollable modal-xl", modalDialogClass: "modal-dialog-scrollable modal-xl",
}); });
const castPerson = ref(); const castPerson = ref();
@ -146,214 +146,209 @@ const castThirdparty = ref();
const castNew = ref(); const castNew = ref();
const hasResourceComment = computed(() => { const hasResourceComment = computed(() => {
return ( return (
typeof props.parent !== "undefined" && typeof props.parent !== "undefined" &&
props.parent !== null && props.parent !== null &&
props.action === "show" && props.action === "show" &&
props.parent.type === "accompanying_period_resource" && props.parent.type === "accompanying_period_resource" &&
props.parent.comment !== null && props.parent.comment !== null &&
props.parent.comment !== "" props.parent.comment !== ""
); );
}); });
const classAction = computed(() => { const classAction = computed(() => {
switch (props.action) { switch (props.action) {
case "show": case "show":
return "btn-show"; return "btn-show";
case "edit": case "edit":
return "btn-update"; return "btn-update";
case "create": case "create":
return "btn-create"; return "btn-create";
case "addContact": case "addContact":
return "btn-tpchild"; return "btn-tpchild";
default: default:
return ""; return "";
} }
}); });
const titleAction = computed(() => { const titleAction = computed(() => {
switch (props.action) { switch (props.action) {
case "show": case "show":
return ACTION_SHOW; return ACTION_SHOW;
case "edit": case "edit":
return ACTION_EDIT; return ACTION_EDIT;
case "create": case "create":
return ACTION_CREATE; return ACTION_CREATE;
case "addContact": case "addContact":
return ACTION_ADDCONTACT; return ACTION_ADDCONTACT;
default: default:
return ""; return "";
} }
}); });
const titleCreate = computed(() => { const titleCreate = computed(() => {
if (typeof props.allowedTypes === "undefined") { if (typeof props.allowedTypes === "undefined") {
return ONTHEFLY_CREATE_TITLE_DEFAULT; return ONTHEFLY_CREATE_TITLE_DEFAULT;
} }
return props.allowedTypes.every((t) => t === "person") return props.allowedTypes.every((t) => t === "person")
? ONTHEFLY_CREATE_TITLE_PERSON ? ONTHEFLY_CREATE_TITLE_PERSON
: props.allowedTypes.every((t) => t === "thirdparty") : props.allowedTypes.every((t) => t === "thirdparty")
? ONTHEFLY_CREATE_TITLE_THIRDPARTY ? ONTHEFLY_CREATE_TITLE_THIRDPARTY
: ONTHEFLY_CREATE_TITLE_DEFAULT; : ONTHEFLY_CREATE_TITLE_DEFAULT;
}); });
const titleModal = computed(() => { const titleModal = computed(() => {
switch (props.action) { switch (props.action) {
case "show": case "show":
if (props.type == "person") { if (props.type == "person") {
return ONTHEFLY_SHOW_PERSON; return ONTHEFLY_SHOW_PERSON;
} else if (props.type == "thirdparty") { } else if (props.type == "thirdparty") {
return ONTHEFLY_SHOW_THIRDPARTY; return ONTHEFLY_SHOW_THIRDPARTY;
} }
break; break;
case "edit": case "edit":
if (props.type == "person") { if (props.type == "person") {
return ONTHEFLY_EDIT_PERSON; return ONTHEFLY_EDIT_PERSON;
} else if (props.type == "thirdparty") { } else if (props.type == "thirdparty") {
return ONTHEFLY_EDIT_THIRDPARTY; return ONTHEFLY_EDIT_THIRDPARTY;
} }
break; break;
case "create": case "create":
return titleCreate.value; return titleCreate.value;
case "addContact": case "addContact":
return ONTHEFLY_ADDCONTACT_TITLE; return ONTHEFLY_ADDCONTACT_TITLE;
default: default:
break; break;
} }
return ""; return "";
}); });
const titleMessage = computed(() => { const titleMessage = computed(() => {
switch (props.type) { switch (props.type) {
case "person": case "person":
return ACTION_REDIRECT_PERSON; return ACTION_REDIRECT_PERSON;
case "thirdparty": case "thirdparty":
return ACTION_REDIRECT_THIRDPARTY; return ACTION_REDIRECT_THIRDPARTY;
default: default:
return ""; return "";
} }
}); });
const buttonMessage = computed(() => { const buttonMessage = computed(() => {
switch (props.type) { switch (props.type) {
case "person": case "person":
return ONTHEFLY_SHOW_FILE_PERSON; return ONTHEFLY_SHOW_FILE_PERSON;
case "thirdparty": case "thirdparty":
return ONTHEFLY_SHOW_FILE_THIRDPARTY; return ONTHEFLY_SHOW_FILE_THIRDPARTY;
default: default:
return ONTHEFLY_SHOW_FILE_DEFAULT; return ONTHEFLY_SHOW_FILE_DEFAULT;
} }
}); });
const isDisplayBadge = computed(() => { const isDisplayBadge = computed(() => {
return props.displayBadge === true && props.buttonText !== null; return props.displayBadge === true && props.buttonText !== null;
}); });
const badgeType = computed(() => { const badgeType = computed(() => {
return "entity-" + props.type + " badge-" + props.type; return "entity-" + props.type + " badge-" + props.type;
}); });
const getReturnPath = computed(() => { const getReturnPath = computed(() => {
return `?returnPath=${window.location.pathname}${window.location.search}${window.location.hash}`; return `?returnPath=${window.location.pathname}${window.location.search}${window.location.hash}`;
}); });
function closeModal() { function closeModal() {
modal.value.showModal = false; modal.value.showModal = false;
} }
function openModal() { function openModal() {
modal.value.showModal = true; modal.value.showModal = true;
} }
function changeActionTo(action) { function changeActionTo(action) {
console.log(action); console.log(action);
// Not reactive in setup, but you can emit or use a ref if needed // Not reactive in setup, but you can emit or use a ref if needed
} }
function saveAction() { function saveAction() {
let type = props.type, let type = props.type,
data = {}; data = {};
switch (type) { switch (type) {
case "person": case "person":
data = castPerson.value?.$data.person; data = castPerson.value?.$data.person;
break; break;
case "thirdparty": case "thirdparty":
data = castThirdparty.value?.$data.thirdparty; data = castThirdparty.value?.$data.thirdparty;
break; break;
default: default:
if (typeof props.type === "undefined") { if (typeof props.type === "undefined") {
if (props.action === "addContact") { if (props.action === "addContact") {
type = "thirdparty"; type = "thirdparty";
data = castThirdparty.value?.$data.thirdparty; data = castThirdparty.value?.$data.thirdparty;
data.parent = { data.parent = {
type: "thirdparty", type: "thirdparty",
id: props.parent.id, id: props.parent.id,
}; };
data.civility = data.civility =
data.civility !== null data.civility !== null
? { ? {
type: "chill_main_civility", type: "chill_main_civility",
id: data.civility.id, 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 { : null;
throw "error with object type"; data.profession = data.profession !== "" ? data.profession : "";
} } else {
} type = castNew.value.radioType;
emit("saveFormOnTheFly", { type: type, data: data }); 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";
}
}
emit("saveFormOnTheFly", { type: type, data: data });
} }
function buildLocation(id, type) { function buildLocation(id, type) {
if (type === "person") { if (type === "person") {
return encodeURI(`/fr/person/${id}/general${getReturnPath.value}`); return encodeURI(`/fr/person/${id}/general${getReturnPath.value}`);
} else if (type === "thirdparty") { } else if (type === "thirdparty") {
return encodeURI(`/fr/3party/3party/${id}/view${getReturnPath.value}`); return encodeURI(`/fr/3party/3party/${id}/view${getReturnPath.value}`);
} }
} }
defineExpose({ defineExpose({
openModal, openModal,
closeModal, closeModal,
changeActionTo, changeActionTo,
saveAction, saveAction,
castPerson, castPerson,
castThirdparty, castThirdparty,
castNew, castNew,
hasResourceComment, hasResourceComment,
modal, modal,
isDisplayBadge, isDisplayBadge,
Modal, Modal,
}); });
</script> </script>
<style lang="css" scoped> <style lang="css" scoped>
a { a {
cursor: pointer; cursor: pointer;
} }
/* .btn-add-contact { /* .btn-add-contact {

View File

@ -1,41 +1,37 @@
<template> <template>
<div class="grey-card"> <div class="grey-card">
<ul :class="listClasses" v-if="picked.length && displayPicked"> <ul :class="listClasses" v-if="picked.length && displayPicked">
<li <li v-for="p in picked" @click="removeEntity(p)" :key="p.type + p.id">
v-for="p in picked" <span
@click="removeEntity(p)" :class="getBadgeClass(p)"
:key="p.type + p.id" class="chill_denomination"
> :style="getBadgeStyle(p)"
<span >
:class="getBadgeClass(p)" {{ p.text }}
class="chill_denomination" </span>
:style="getBadgeStyle(p)" </li>
> </ul>
{{ p.text }} <ul class="record_actions">
</span> <li class="add-persons">
</li> <add-persons
</ul> :options="addPersonsOptions"
<ul class="record_actions"> :key="uniqid"
<li class="add-persons"> :buttonTitle="translatedListOfTypes"
<add-persons :modalTitle="translatedListOfTypes"
:options="addPersonsOptions" @addNewPersons="addNewEntity"
:key="uniqid" >
:buttonTitle="translatedListOfTypes" </add-persons>
:modalTitle="translatedListOfTypes" </li>
@addNewPersons="addNewEntity" </ul>
>
</add-persons>
</li>
</ul>
<ul class="badge-suggest add-items inline" style="float: right"> <ul class="badge-suggest add-items inline" style="float: right">
<li v-for="s in suggested" :key="s.id" @click="addNewSuggested(s)"> <li v-for="s in suggested" :key="s.id" @click="addNewSuggested(s)">
<span :class="getBadgeClass(s)" :style="getBadgeStyle(s)"> <span :class="getBadgeClass(s)" :style="getBadgeStyle(s)">
{{ s.text }} {{ s.text }}
</span> </span>
</li> </li>
</ul> </ul>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -43,135 +39,135 @@ import { ref, computed, defineProps, defineEmits, defineComponent } from "vue";
import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue"; import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue";
import { Entities, EntityType, SearchOptions } from "ChillPersonAssets/types"; import { Entities, EntityType, SearchOptions } from "ChillPersonAssets/types";
import { import {
PICK_ENTITY_MODAL_TITLE, PICK_ENTITY_MODAL_TITLE,
PICK_ENTITY_USER, PICK_ENTITY_USER,
PICK_ENTITY_USER_GROUP, PICK_ENTITY_USER_GROUP,
PICK_ENTITY_PERSON, PICK_ENTITY_PERSON,
PICK_ENTITY_THIRDPARTY, PICK_ENTITY_THIRDPARTY,
trans, trans,
} from "translator"; } from "translator";
import { addNewEntities } from "ChillMainAssets/types"; import { addNewEntities } from "ChillMainAssets/types";
defineComponent({ defineComponent({
components: { components: {
AddPersons, AddPersons,
}, },
}); });
const props = defineProps<{ const props = defineProps<{
multiple: boolean; multiple: boolean;
types: EntityType[]; types: EntityType[];
picked: Entities[]; picked: Entities[];
uniqid: string; uniqid: string;
removableIfSet?: boolean; removableIfSet?: boolean;
displayPicked?: boolean; displayPicked?: boolean;
suggested?: Entities[]; suggested?: Entities[];
label?: string; label?: string;
}>(); }>();
const emits = defineEmits<{ const emits = defineEmits<{
(e: "addNewEntity", payload: { entity: Entities }): void; (e: "addNewEntity", payload: { entity: Entities }): void;
(e: "removeEntity", payload: { entity: Entities }): void; (e: "removeEntity", payload: { entity: Entities }): void;
(e: "addNewEntityProcessEnded"): void; (e: "addNewEntityProcessEnded"): void;
}>(); }>();
const addPersons = ref(); const addPersons = ref();
const addPersonsOptions = computed( const addPersonsOptions = computed(
() => () =>
({ ({
uniq: !props.multiple, uniq: !props.multiple,
type: props.types, type: props.types,
priority: null, priority: null,
button: { button: {
size: "btn-sm", size: "btn-sm",
class: "btn-submit", class: "btn-submit",
}, },
}) as SearchOptions, }) as SearchOptions,
); );
const translatedListOfTypes = computed(() => { const translatedListOfTypes = computed(() => {
if (props.label !== undefined && props.label !== "") { if (props.label !== undefined && props.label !== "") {
return props.label; return props.label;
}
const translatedTypes = props.types.map((type: EntityType) => {
switch (type) {
case "user":
return trans(PICK_ENTITY_USER, {
count: props.multiple ? 2 : 1,
});
case "person":
return trans(PICK_ENTITY_PERSON, {
count: props.multiple ? 2 : 1,
});
case "thirdparty":
return trans(PICK_ENTITY_THIRDPARTY, {
count: props.multiple ? 2 : 1,
});
case "user_group":
return trans(PICK_ENTITY_USER_GROUP, {
count: props.multiple ? 2 : 1,
});
} }
});
const translatedTypes = props.types.map((type: EntityType) => { return `${trans(PICK_ENTITY_MODAL_TITLE, {
switch (type) { count: props.multiple ? 2 : 1,
case "user": })} ${translatedTypes.join(", ")}`;
return trans(PICK_ENTITY_USER, {
count: props.multiple ? 2 : 1,
});
case "person":
return trans(PICK_ENTITY_PERSON, {
count: props.multiple ? 2 : 1,
});
case "third_party":
return trans(PICK_ENTITY_THIRDPARTY, {
count: props.multiple ? 2 : 1,
});
case "user_group":
return trans(PICK_ENTITY_USER_GROUP, {
count: props.multiple ? 2 : 1,
});
}
});
return `${trans(PICK_ENTITY_MODAL_TITLE, {
count: props.multiple ? 2 : 1,
})} ${translatedTypes.join(", ")}`;
}); });
const listClasses = computed(() => ({ const listClasses = computed(() => ({
"badge-suggest": true, "badge-suggest": true,
"remove-items": props.removableIfSet !== false, "remove-items": props.removableIfSet !== false,
inline: true, inline: true,
})); }));
function addNewSuggested(entity: Entities) { function addNewSuggested(entity: Entities) {
emits("addNewEntity", { entity }); emits("addNewEntity", { entity });
} }
function addNewEntity({ selected }: addNewEntities) { function addNewEntity({ selected }: addNewEntities) {
Object.values(selected).forEach((item) => { Object.values(selected).forEach((item) => {
emits("addNewEntity", { entity: item.result }); emits("addNewEntity", { entity: item.result });
}); });
addPersons.value?.resetSearch(); addPersons.value?.resetSearch();
emits("addNewEntityProcessEnded"); emits("addNewEntityProcessEnded");
} }
function removeEntity(entity: Entities) { function removeEntity(entity: Entities) {
if (props.removableIfSet === false) { if (props.removableIfSet === false) {
return; return;
} }
emits("removeEntity", { entity }); emits("removeEntity", { entity });
} }
function getBadgeClass(entities: Entities) { function getBadgeClass(entities: Entities) {
if (entities.type !== "user_group") { if (entities.type !== "user_group") {
return entities.type; return entities.type;
} }
return ""; return "";
} }
function getBadgeStyle(entities: Entities) { function getBadgeStyle(entities: Entities) {
if (entities.type === "user_group") { if (entities.type === "user_group") {
return [ return [
`ul.badge-suggest li > span { `ul.badge-suggest li > span {
color: ${entities.foregroundColor}!important; color: ${entities.foregroundColor}!important;
border-bottom-color: ${entities.backgroundColor}; border-bottom-color: ${entities.backgroundColor};
}`, }`,
]; ];
} }
return []; return [];
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.grey-card { .grey-card {
background: #f8f9fa; background: #f8f9fa;
border-radius: 8px; border-radius: 8px;
padding: 1.5rem; padding: 1.5rem;
min-height: 160px; min-height: 160px;
} }
.btn-check:checked + .btn, .btn-check:checked + .btn,
@ -179,94 +175,94 @@ function getBadgeStyle(entities: Entities) {
.btn:first-child:active, .btn:first-child:active,
.btn.active, .btn.active,
.btn.show { .btn.show {
color: white; color: white;
box-shadow: 0 0 0 0.2rem var(--bs-chill-green); box-shadow: 0 0 0 0.2rem var(--bs-chill-green);
outline: 0; outline: 0;
} }
.as-user-group { .as-user-group {
display: inline-block; display: inline-block;
} }
ul.badge-suggest { ul.badge-suggest {
list-style-type: none; list-style-type: none;
padding-left: 0; padding-left: 0;
margin-bottom: 0px; margin-bottom: 0px;
} }
ul.badge-suggest li > span { ul.badge-suggest li > span {
white-space: normal; white-space: normal;
text-align: start; text-align: start;
margin-bottom: 3px; margin-bottom: 3px;
} }
ul.badge-suggest.inline li { ul.badge-suggest.inline li {
display: inline-block; display: inline-block;
margin-right: 0.2em; margin-right: 0.2em;
} }
ul.badge-suggest.add-items li { ul.badge-suggest.add-items li {
position: relative; position: relative;
} }
ul.badge-suggest.add-items li span { ul.badge-suggest.add-items li span {
cursor: pointer; cursor: pointer;
padding-left: 2rem; padding-left: 2rem;
} }
ul.badge-suggest.add-items li span:hover { ul.badge-suggest.add-items li span:hover {
color: #ced4da; color: #ced4da;
} }
ul.badge-suggest.add-items li > span:before { ul.badge-suggest.add-items li > span:before {
font: normal normal normal 13px ForkAwesome; font: normal normal normal 13px ForkAwesome;
margin-right: 1.8em; margin-right: 1.8em;
content: "\f067"; content: "\f067";
color: var(--bs-success); color: var(--bs-success);
position: absolute; position: absolute;
display: block; display: block;
top: 50%; top: 50%;
left: 0.75rem; left: 0.75rem;
-webkit-transform: translateY(-50%); -webkit-transform: translateY(-50%);
-moz-transform: translateY(-50%); -moz-transform: translateY(-50%);
-ms-transform: translateY(-50%); -ms-transform: translateY(-50%);
transform: translateY(-50%); transform: translateY(-50%);
} }
ul.badge-suggest.remove-items li { ul.badge-suggest.remove-items li {
position: relative; position: relative;
} }
ul.badge-suggest.remove-items li span { ul.badge-suggest.remove-items li span {
cursor: pointer; cursor: pointer;
padding-left: 2rem; padding-left: 2rem;
} }
ul.badge-suggest.remove-items li span:hover { ul.badge-suggest.remove-items li span:hover {
color: #ced4da; color: #ced4da;
} }
ul.badge-suggest.remove-items li > span:before { ul.badge-suggest.remove-items li > span:before {
font: normal normal normal 13px ForkAwesome; font: normal normal normal 13px ForkAwesome;
margin-right: 1.8em; margin-right: 1.8em;
content: "\f1f8"; content: "\f1f8";
color: var(--bs-danger); color: var(--bs-danger);
position: absolute; position: absolute;
display: block; display: block;
top: 50%; top: 50%;
left: 0.75rem; left: 0.75rem;
-webkit-transform: translateY(-50%); -webkit-transform: translateY(-50%);
-moz-transform: translateY(-50%); -moz-transform: translateY(-50%);
-ms-transform: translateY(-50%); -ms-transform: translateY(-50%);
transform: translateY(-50%); transform: translateY(-50%);
} }
ul.badge-suggest li > span { ul.badge-suggest li > span {
margin: 0.2rem 0.1rem; margin: 0.2rem 0.1rem;
display: inline-block; display: inline-block;
padding: 0 1em 0 2.2em !important; padding: 0 1em 0 2.2em !important;
background-color: #fff; background-color: #fff;
border: 1px solid #dee2e6; border: 1px solid #dee2e6;
border-bottom-width: 3px; border-bottom-width: 3px;
border-bottom-style: solid; border-bottom-style: solid;
border-radius: 6px; border-radius: 6px;
font-size: 0.75em; font-size: 0.75em;
font-weight: 700; font-weight: 700;
} }
ul.badge-suggest li > span.person { ul.badge-suggest li > span.person {
border-bottom-color: #43b29d; border-bottom-color: #43b29d;
} }
ul.badge-suggest li > span.thirdparty { ul.badge-suggest li > span.thirdparty {
border-bottom-color: rgb(198.9, 72, 98.1); border-bottom-color: rgb(198.9, 72, 98.1);
} }
</style> </style>

View File

@ -1,309 +1,315 @@
import { StoredObject } from "ChillDocStoreAssets/types"; import { StoredObject } from "ChillDocStoreAssets/types";
import { import {
Address, Address,
Center, Center,
Civility, Civility,
DateTime, DateTime,
User, User,
UserGroup, UserGroup,
Household, Household,
ThirdParty, WorkflowAvailable,
WorkflowAvailable, Scope,
Scope, Job,
Job, PrivateCommentEmbeddable,
PrivateCommentEmbeddable,
} from "../../../ChillMainBundle/Resources/public/types"; } from "../../../ChillMainBundle/Resources/public/types";
import { Thirdparty } from "../../../ChillThirdPartyBundle/Resources/public/types"; import { Thirdparty } from "../../../ChillThirdPartyBundle/Resources/public/types";
import { Calendar } from "../../../ChillCalendarBundle/Resources/public/types"; import { Calendar } from "../../../ChillCalendarBundle/Resources/public/types";
export interface AltName {
label: string;
key: string;
}
export interface Person { export interface Person {
id: number; id: number;
type: "person"; type: "person";
text: string; text: string;
textAge: string; textAge: string;
firstName: string; firstName: string;
lastName: string; lastName: string;
current_household_address: Address | null; altNames: AltName[];
birthdate: DateTime | null; suffixText: string;
deathdate: DateTime | null; current_household_address: Address | null;
age: number; birthdate: DateTime | null;
phonenumber: string; deathdate: DateTime | null;
mobilenumber: string; age: number;
email: string; phonenumber: string;
gender: "woman" | "man" | "other"; mobilenumber: string;
centers: Center[]; email: string;
civility: Civility | null; gender: "woman" | "man" | "other";
current_household_id: number; centers: Center[];
current_residential_addresses: Address[]; civility: Civility | null;
current_household_id: number;
current_residential_addresses: Address[];
} }
export interface AccompanyingPeriod { export interface AccompanyingPeriod {
id: number; id: number;
addressLocation?: Address | null; addressLocation?: Address | null;
administrativeLocation?: Location | null; administrativeLocation?: Location | null;
calendars: Calendar[]; calendars: Calendar[];
closingDate?: Date | null; closingDate?: Date | null;
closingMotive?: ClosingMotive | null; closingMotive?: ClosingMotive | null;
comments: Comment[]; comments: Comment[];
confidential: boolean; confidential: boolean;
createdAt?: Date | null; createdAt?: Date | null;
createdBy?: User | null; createdBy?: User | null;
emergency: boolean; emergency: boolean;
intensity?: "occasional" | "regular"; intensity?: "occasional" | "regular";
job?: Job | null; job?: Job | null;
locationHistories: AccompanyingPeriodLocationHistory[]; locationHistories: AccompanyingPeriodLocationHistory[];
openingDate?: Date | null; openingDate?: Date | null;
origin?: Origin | null; origin?: Origin | null;
participations: AccompanyingPeriodParticipation[]; participations: AccompanyingPeriodParticipation[];
personLocation?: Person | null; personLocation?: Person | null;
pinnedComment?: Comment | null; pinnedComment?: Comment | null;
preventUserIsChangedNotification: boolean; preventUserIsChangedNotification: boolean;
remark: string; remark: string;
requestorAnonymous: boolean; requestorAnonymous: boolean;
requestorPerson?: Person | null; requestorPerson?: Person | null;
requestorThirdParty?: Thirdparty | null; requestorThirdParty?: Thirdparty | null;
resources: AccompanyingPeriodResource[]; resources: AccompanyingPeriodResource[];
scopes: Scope[]; scopes: Scope[];
socialIssues: SocialIssue[]; socialIssues: SocialIssue[];
step?: step?:
| "CLOSED" | "CLOSED"
| "CONFIRMED" | "CONFIRMED"
| "CONFIRMED_INACTIVE_SHORT" | "CONFIRMED_INACTIVE_SHORT"
| "CONFIRMED_INACTIVE_LONG" | "CONFIRMED_INACTIVE_LONG"
| "DRAFT"; | "DRAFT";
} }
export interface AccompanyingPeriodWork { export interface AccompanyingPeriodWork {
id: number; id: number;
accompanyingPeriod?: AccompanyingPeriod; accompanyingPeriod?: AccompanyingPeriod;
accompanyingPeriodWorkEvaluations: AccompanyingPeriodWorkEvaluation[]; accompanyingPeriodWorkEvaluations: AccompanyingPeriodWorkEvaluation[];
createdAt?: string; createdAt?: string;
createdAutomatically: boolean; createdAutomatically: boolean;
createdAutomaticallyReason: string; createdAutomaticallyReason: string;
createdBy: User; createdBy: User;
endDate?: string; endDate?: string;
goals: AccompanyingPeriodWorkGoal[]; goals: AccompanyingPeriodWorkGoal[];
handlingThierParty?: Thirdparty; handlingThierParty?: Thirdparty;
note: string; note: string;
persons: Person[]; persons: Person[];
privateComment: PrivateCommentEmbeddable; privateComment: PrivateCommentEmbeddable;
referrersHistory: AccompanyingPeriodWorkReferrerHistory[]; referrersHistory: AccompanyingPeriodWorkReferrerHistory[];
results: Result[]; results: Result[];
socialAction?: SocialAction; socialAction?: SocialAction;
startDate?: string; startDate?: string;
thirdParties: Thirdparty[]; thirdParties: Thirdparty[];
updatedAt?: string; updatedAt?: string;
updatedBy: User; updatedBy: User;
version: number; version: number;
} }
export interface SocialAction { export interface SocialAction {
id: number; id: number;
parent?: SocialAction | null; parent?: SocialAction | null;
children: SocialAction[]; children: SocialAction[];
issue?: SocialIssue | null; issue?: SocialIssue | null;
ordering: number; ordering: number;
title: { title: {
fr: string; fr: string;
}; };
defaultNotificationDelay?: string | null; defaultNotificationDelay?: string | null;
desactivationDate?: string | null; desactivationDate?: string | null;
evaluations: Evaluation[]; evaluations: Evaluation[];
goals: Goal[]; goals: Goal[];
results: Result[]; results: Result[];
} }
export interface AccompanyingPeriodResource { export interface AccompanyingPeriodResource {
id: number; id: number;
accompanyingPeriod: AccompanyingPeriod; accompanyingPeriod: AccompanyingPeriod;
comment?: string | null; comment?: string | null;
person?: Person | null; person?: Person | null;
thirdParty?: Thirdparty | null; thirdParty?: Thirdparty | null;
} }
export interface Origin { export interface Origin {
id: number; id: number;
label: { label: {
fr: string; fr: string;
}; };
noActiveAfter: DateTime; noActiveAfter: DateTime;
} }
export interface ClosingMotive { export interface ClosingMotive {
id: number; id: number;
active: boolean; active: boolean;
name: { name: {
fr: string; fr: string;
}; };
ordering: number; ordering: number;
isCanceledAccompanyingPeriod: boolean; isCanceledAccompanyingPeriod: boolean;
parent?: ClosingMotive | null; parent?: ClosingMotive | null;
children: ClosingMotive[]; children: ClosingMotive[];
} }
export interface AccompanyingPeriodParticipation { export interface AccompanyingPeriodParticipation {
id: number; id: number;
startDate: DateTime; startDate: DateTime;
endDate?: DateTime | null; endDate?: DateTime | null;
accompanyingPeriod: AccompanyingPeriod; accompanyingPeriod: AccompanyingPeriod;
person: Person; person: Person;
} }
export interface AccompanyingPeriodLocationHistory { export interface AccompanyingPeriodLocationHistory {
id: number; id: number;
startDate: DateTime; startDate: DateTime;
endDate?: DateTime | null; endDate?: DateTime | null;
addressLocation?: Address | null; addressLocation?: Address | null;
period: AccompanyingPeriod; period: AccompanyingPeriod;
personLocation?: Person | null; personLocation?: Person | null;
} }
export interface SocialIssue { export interface SocialIssue {
id: number; id: number;
parent?: SocialIssue | null; parent?: SocialIssue | null;
children: SocialIssue[]; children: SocialIssue[];
socialActions?: SocialAction[] | null; socialActions?: SocialAction[] | null;
ordering: number; ordering: number;
title: { title: {
fr: string; fr: string;
}; };
desactivationDate?: string | null; desactivationDate?: string | null;
} }
export interface Goal { export interface Goal {
id: number; id: number;
results: Result[]; results: Result[];
socialActions?: SocialAction[] | null; socialActions?: SocialAction[] | null;
title: { title: {
fr: string; fr: string;
}; };
} }
export interface AccompanyingPeriodWorkGoal { export interface AccompanyingPeriodWorkGoal {
id: number; id: number;
accompanyingPeriodWork: AccompanyingPeriodWork; accompanyingPeriodWork: AccompanyingPeriodWork;
goal: Goal; goal: Goal;
note: string; note: string;
results: Result[]; results: Result[];
} }
export interface AccompanyingPeriodWorkEvaluation { export interface AccompanyingPeriodWorkEvaluation {
accompanyingPeriodWork: AccompanyingPeriodWork | null; accompanyingPeriodWork: AccompanyingPeriodWork | null;
comment: string; comment: string;
createdAt: DateTime | null; createdAt: DateTime | null;
createdBy: User | null; createdBy: User | null;
documents: AccompanyingPeriodWorkEvaluationDocument[]; documents: AccompanyingPeriodWorkEvaluationDocument[];
endDate: DateTime | null; endDate: DateTime | null;
evaluation: Evaluation | null; evaluation: Evaluation | null;
id: number | null; id: number | null;
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
key: any; key: any;
maxDate: DateTime | null; maxDate: DateTime | null;
startDate: DateTime | null; startDate: DateTime | null;
updatedAt: DateTime | null; updatedAt: DateTime | null;
updatedBy: User | null; updatedBy: User | null;
warningInterval: string | null; warningInterval: string | null;
timeSpent: number | null; timeSpent: number | null;
} }
export interface Evaluation { export interface Evaluation {
id: number; id: number;
url: string; url: string;
socialActions: SocialAction[]; socialActions: SocialAction[];
title: { title: {
fr: string; fr: string;
}; };
active: boolean; active: boolean;
delay: string; delay: string;
notificationDelay: string; notificationDelay: string;
} }
export interface AccompanyingPeriodWorkReferrerHistory { export interface AccompanyingPeriodWorkReferrerHistory {
id: number; id: number;
accompanyingPeriodWork: AccompanyingPeriodWork; accompanyingPeriodWork: AccompanyingPeriodWork;
user: User; user: User;
startDate: DateTime; startDate: DateTime;
endDate: DateTime | null; endDate: DateTime | null;
createdAt: DateTime; createdAt: DateTime;
updatedAt: DateTime | null; updatedAt: DateTime | null;
createdBy: User; createdBy: User;
updatedBy: User | null; updatedBy: User | null;
} }
export interface AccompanyingPeriodWorkEvaluationDocument { export interface AccompanyingPeriodWorkEvaluationDocument {
id: number; id: number;
type: "accompanying_period_work_evaluation_document"; type: "accompanying_period_work_evaluation_document";
storedObject: StoredObject; storedObject: StoredObject;
title: string; title: string;
createdAt: DateTime | null; createdAt: DateTime | null;
createdBy: User | null; createdBy: User | null;
updatedAt: DateTime | null; updatedAt: DateTime | null;
updatedBy: User | null; updatedBy: User | null;
workflows_availables: WorkflowAvailable[]; workflows_availables: WorkflowAvailable[];
workflows: object[]; workflows: object[];
} }
export type EntityType = export type EntityType =
| "user_group" | "user_group"
| "user" | "user"
| "person" | "person"
| "third_party" | "thirdparty"
| "household"; | "household";
export type Entities = (UserGroup | User | Person | ThirdParty | Household) & { export type Entities = (UserGroup | User | Person | Thirdparty | Household) & {
address?: Address | null; address?: Address | null;
kind?: string; kind?: string;
text?: string; text?: string;
profession?: string; profession?: string;
}; };
export type Result = Entities & { export type Result = Entities & {
parent?: Entities | null; parent?: Entities | null;
}; };
export interface Suggestion { export interface Suggestion {
key: string; key: string;
relevance: number; relevance: number;
result: Result; result: Result;
} }
export interface SearchPagination { export interface SearchPagination {
first: number; first: number;
items_per_page: number; items_per_page: number;
next: number | null; next: number | null;
previous: number | null; previous: number | null;
more: boolean; more: boolean;
} }
export interface Search { export interface Search {
count: number; count: number;
pagination: SearchPagination; pagination: SearchPagination;
results: Suggestion[]; results: Suggestion[];
} }
export interface SearchOptions { export interface SearchOptions {
uniq: boolean; uniq: boolean;
type: string[]; type: string[];
priority: number | null; priority: number | null;
button: { button: {
size: string; size: string;
class: string; class: string;
type: string; type: string;
display: string; display: string;
}; };
} }
export class MakeFetchException extends Error { export class MakeFetchException extends Error {
sta: number; sta: number;
txt: string; txt: string;
violations: unknown | null; violations: unknown | null;
constructor(txt: string, sta: number, violations: unknown | null = null) { constructor(txt: string, sta: number, violations: unknown | null = null) {
super(txt); super(txt);
this.name = "ValidationException"; this.name = "ValidationException";
this.sta = sta; this.sta = sta;
this.txt = txt; this.txt = txt;
this.violations = violations; this.violations = violations;
Object.setPrototypeOf(this, MakeFetchException.prototype); Object.setPrototypeOf(this, MakeFetchException.prototype);
} }
} }

View File

@ -23,6 +23,7 @@ import { computed, defineProps } from "vue";
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue"; import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
import BadgeEntity from "ChillMainAssets/vuejs/_components/BadgeEntity.vue"; import BadgeEntity from "ChillMainAssets/vuejs/_components/BadgeEntity.vue";
import PersonText from "ChillPersonAssets/vuejs/_components/Entity/PersonText.vue"; import PersonText from "ChillPersonAssets/vuejs/_components/Entity/PersonText.vue";
import { Person } from "ChillPersonAssets/types";
function formatDate(dateString: string | undefined, format: string) { function formatDate(dateString: string | undefined, format: string) {
if (!dateString) return ""; if (!dateString) return "";
@ -36,15 +37,7 @@ function formatDate(dateString: string | undefined, format: string) {
const props = defineProps<{ const props = defineProps<{
item: { item: {
result: { result: Person; // add other fields as needed
id: number | string;
birthdate: { datetime: string } | null;
current_household_address: {
text: string;
postcode: { name: string };
} | null;
// add other fields as needed
};
}; };
}>(); }>();

View File

@ -36,8 +36,8 @@ import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
import BadgeEntity from "ChillMainAssets/vuejs/_components/BadgeEntity.vue"; import BadgeEntity from "ChillMainAssets/vuejs/_components/BadgeEntity.vue";
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods"; import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
import { useToast } from "vue-toast-notification"; import { useToast } from "vue-toast-notification";
import { ThirdParty } from "ChillMainAssets/types";
import { Result, Suggestion } from "ChillPersonAssets/types"; import { Result, Suggestion } from "ChillPersonAssets/types";
import { Thirdparty } from "src/Bundle/ChillThirdPartyBundle/Resources/public/types";
interface TypeThirdPartyProps { interface TypeThirdPartyProps {
item: Suggestion; item: Suggestion;
@ -76,7 +76,7 @@ const getAddress = computed(() => {
return null; return null;
}); });
function saveFormOnTheFly({ data }: { data: ThirdParty }) { function saveFormOnTheFly({ data }: { data: Thirdparty }) {
makeFetch("POST", "/api/1.0/thirdparty/thirdparty.json", data) makeFetch("POST", "/api/1.0/thirdparty/thirdparty.json", data)
.then((response: unknown) => { .then((response: unknown) => {
const result = response as Result; const result = response as Result;

View File

@ -23,22 +23,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, toRefs } from "vue"; import { computed, toRefs } from "vue";
import { trans, RENDERBOX_YEARS_OLD } from "translator"; import { trans, RENDERBOX_YEARS_OLD } from "translator";
import { AltName, Person } from "ChillPersonAssets/types";
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<{ const props = defineProps<{
person: Person; person: Person;

View File

@ -1,47 +1,49 @@
import { import {
Address, Address,
Center, Center,
Civility, Civility,
DateTime, DateTime,
User, User,
} from "ChillMainAssets/types"; } from "ChillMainAssets/types";
export interface Thirdparty { export interface Thirdparty {
acronym: string | null; type: "thirdparty";
active: boolean; text: string;
address: Address | null; acronym: string | null;
canonicalized: string | null; active: boolean;
categories: ThirdpartyCategory[]; address: Address | null;
centers: Center[]; canonicalized: string | null;
children: Thirdparty[]; categories: ThirdpartyCategory[];
civility: Civility | null; centers: Center[];
comment: string | null; children: Thirdparty[];
contactDataAnonymous: boolean; civility: Civility | null;
createdAt: DateTime; comment: string | null;
createdBy: User | null; contactDataAnonymous: boolean;
email: string | null; createdAt: DateTime;
firstname: string | null; createdBy: User | null;
id: number | null; email: string | null;
kind: string; firstname: string | null;
name: string; id: number | null;
nameCompany: string | null; kind: string;
parent: Thirdparty | null; name: string;
profession: string; nameCompany: string | null;
telephone: string | null; parent: Thirdparty | null;
thirdPartyTypes: ThirdpartyType[] | null; profession: string;
updatedAt: DateTime | null; telephone: string | null;
updatedBy: User | null; thirdPartyTypes: ThirdpartyType[] | null;
updatedAt: DateTime | null;
updatedBy: User | null;
} }
interface ThirdpartyType { interface ThirdpartyType {
key: string; key: string;
value: string; value: string;
} }
export interface ThirdpartyCategory { export interface ThirdpartyCategory {
id: number; id: number;
active: boolean; active: boolean;
name: { name: {
fr: string; fr: string;
}; };
} }

View File

@ -1,17 +1,17 @@
import { import {
DateTime, DateTime,
TranslatableString, TranslatableString,
User, User,
UserGroupOrUser, UserGroupOrUser,
} from "ChillMainAssets/types"; } from "ChillMainAssets/types";
import { Person } from "ChillPersonAssets/types"; import { Person } from "ChillPersonAssets/types";
import {Thirdparty} from "../../../../ChillThirdPartyBundle/Resources/public/types"; import { Thirdparty } from "../../../../ChillThirdPartyBundle/Resources/public/types";
export interface Motive { export interface Motive {
type: "ticket_motive"; type: "ticket_motive";
id: number; id: number;
active: boolean; active: boolean;
label: TranslatableString; label: TranslatableString;
} }
export type TicketState = "open" | "closed"; export type TicketState = "open" | "closed";
@ -19,134 +19,135 @@ export type TicketState = "open" | "closed";
export type TicketEmergencyState = "yes" | "no"; export type TicketEmergencyState = "yes" | "no";
interface TicketHistory<T extends string, D extends object> { interface TicketHistory<T extends string, D extends object> {
event_type: T; event_type: T;
at: DateTime; at: DateTime;
by: User; by: User;
data: D; data: D;
} }
export interface PersonHistory { export interface PersonHistory {
type: "ticket_person_history"; type: "ticket_person_history";
id: number; id: number;
startDate: DateTime; startDate: DateTime;
endDate: null | DateTime; endDate: null | DateTime;
person: Person; person: Person;
removedBy: null; removedBy: null;
createdBy: User | null; createdBy: User | null;
createdAt: DateTime | null; createdAt: DateTime | null;
} }
export interface MotiveHistory { export interface MotiveHistory {
type: "ticket_motive_history"; type: "ticket_motive_history";
id: number; id: number;
startDate: null; startDate: null;
endDate: null | DateTime; endDate: null | DateTime;
motive: Motive; motive: Motive;
createdBy: User | null; createdBy: User | null;
createdAt: DateTime | null; createdAt: DateTime | null;
} }
export interface Comment { export interface Comment {
type: "ticket_comment"; type: "ticket_comment";
id: number; id: number;
content: string; content: string;
createdBy: User | null; createdBy: User | null;
createdAt: DateTime | null; createdAt: DateTime | null;
updatedBy: User | null; updatedBy: User | null;
updatedAt: DateTime | null; updatedAt: DateTime | null;
} }
export interface AddresseeHistory { export interface AddresseeHistory {
type: "ticket_addressee_history"; type: "ticket_addressee_history";
id: number; id: number;
startDate: DateTime | null; startDate: DateTime | null;
addressee: UserGroupOrUser; addressee: UserGroupOrUser;
endDate: DateTime | null; endDate: DateTime | null;
removedBy: User | null; removedBy: User | null;
createdBy: User | null; createdBy: User | null;
createdAt: DateTime | null; createdAt: DateTime | null;
updatedBy: User | null; updatedBy: User | null;
updatedAt: DateTime | null; updatedAt: DateTime | null;
} }
export interface AddresseeState { export interface AddresseeState {
addressees: UserGroupOrUser[]; addressees: UserGroupOrUser[];
} }
export interface PersonsState { export interface PersonsState {
persons: Person[]; persons: Person[];
} }
export interface CallerState { export interface CallerState {
new_caller: Person | null; new_caller: Person | Thirdparty | null;
} }
export interface StateChange { export interface StateChange {
new_state: TicketState; new_state: TicketState;
} }
export interface EmergencyChange { export interface EmergencyChange {
new_emergency: TicketEmergencyState; new_emergency: TicketEmergencyState;
} }
export interface CreateTicketState { export interface CreateTicketState {
by: User; by: User;
} }
export type AddCommentEvent = TicketHistory<"add_comment", Comment>; export type AddCommentEvent = TicketHistory<"add_comment", Comment>;
export type SetMotiveEvent = TicketHistory<"set_motive", MotiveHistory>; export type SetMotiveEvent = TicketHistory<"set_motive", MotiveHistory>;
export type AddPersonEvent = TicketHistory<"add_person", PersonHistory>; export type AddPersonEvent = TicketHistory<"add_person", PersonHistory>;
export type AddresseesStateEvent = TicketHistory< export type AddresseesStateEvent = TicketHistory<
"addressees_state", "addressees_state",
AddresseeState AddresseeState
>; >;
export type CreateTicketEvent = TicketHistory< export type CreateTicketEvent = TicketHistory<
"create_ticket", "create_ticket",
CreateTicketState CreateTicketState
>; >;
export type PersonStateEvent = TicketHistory<"persons_state", PersonsState>; export type PersonStateEvent = TicketHistory<"persons_state", PersonsState>;
export type ChangeStateEvent = TicketHistory<"state_change", StateChange>; export type ChangeStateEvent = TicketHistory<"state_change", StateChange>;
export type EmergencyStateEvent = TicketHistory< export type EmergencyStateEvent = TicketHistory<
"emergency_change", "emergency_change",
EmergencyChange EmergencyChange
>; >;
export type CallerStateEvent = TicketHistory<"set_caller", CallerState>; export type CallerStateEvent = TicketHistory<"set_caller", CallerState>;
export type TicketHistoryLine = export type TicketHistoryLine =
| AddPersonEvent | AddPersonEvent
| CreateTicketEvent | CreateTicketEvent
| AddCommentEvent | AddCommentEvent
| SetMotiveEvent | SetMotiveEvent
| AddresseesStateEvent | AddresseesStateEvent
| PersonStateEvent | PersonStateEvent
| ChangeStateEvent | ChangeStateEvent
| EmergencyStateEvent | EmergencyStateEvent
| CallerStateEvent; | CallerStateEvent;
interface BaseTicket<T extends "ticket_ticket:simple"|"ticket_ticket:extended" = "ticket_ticket:simple"> { interface BaseTicket<
type_extended: T; T extends
type: "ticket_ticket"; | "ticket_ticket:simple"
id: number; | "ticket_ticket:extended" = "ticket_ticket:simple",
externalRef: string; > {
currentAddressees: UserGroupOrUser[]; type_extended: T;
currentPersons: Person[]; type: "ticket_ticket";
currentMotive: null | Motive; id: number;
currentState: TicketState | null; externalRef: string;
emergency: TicketEmergencyState | null; currentAddressees: UserGroupOrUser[];
caller: Person | Thirdparty | null; currentPersons: Person[];
} currentMotive: null | Motive;
currentState: TicketState | null;
export interface SimpleTicket extends BaseTicket<"ticket_ticket:simple"> { emergency: TicketEmergencyState | null;
caller: Person | Thirdparty | null;
} }
export interface TicketSimple extends BaseTicket<"ticket_ticket:simple"> { export interface TicketSimple extends BaseTicket<"ticket_ticket:simple"> {
type_extended: "ticket_ticket:simple"; type_extended: "ticket_ticket:simple";
} }
export interface Ticket extends BaseTicket<"ticket_ticket:extended"> { export interface Ticket extends BaseTicket<"ticket_ticket:extended"> {
type_extended: "ticket_ticket:extended"; type_extended: "ticket_ticket:extended";
createdAt: DateTime | null; createdAt: DateTime | null;
createdBy: User | null; createdBy: User | null;
updatedAt: DateTime | null; updatedAt: DateTime | null;
updatedBy: User | null; updatedBy: User | null;
history: TicketHistoryLine[]; history: TicketHistoryLine[];
} }

View File

@ -1,20 +1,20 @@
<template> <template>
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<pick-entity <pick-entity
uniqid="ticket-addressee-selector" uniqid="ticket-addressee-selector"
:types="['user', 'user_group', 'third_party']" :types="['user', 'user_group', 'thirdparty']"
:picked="selectedEntities" :picked="selectedEntities"
:suggested="suggestedValues" :suggested="suggestedValues"
:multiple="true" :multiple="true"
:removable-if-set="true" :removable-if-set="true"
:display-picked="true" :display-picked="true"
:label="trans(CHILL_TICKET_TICKET_ADD_ADDRESSEE_USER_LABEL)" :label="trans(CHILL_TICKET_TICKET_ADD_ADDRESSEE_USER_LABEL)"
@add-new-entity="addNewEntity" @add-new-entity="addNewEntity"
@remove-entity="removeEntity" @remove-entity="removeEntity"
/> />
</div>
</div> </div>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -28,13 +28,13 @@ import { Entities } from "ChillPersonAssets/types";
// Translations // Translations
import { import {
CHILL_TICKET_TICKET_ADD_ADDRESSEE_USER_LABEL, CHILL_TICKET_TICKET_ADD_ADDRESSEE_USER_LABEL,
trans, trans,
} from "translator"; } from "translator";
const props = defineProps<{ const props = defineProps<{
modelValue: Entities[]; modelValue: Entities[];
suggested: Entities[]; suggested: Entities[];
}>(); }>();
const emit = defineEmits<(e: "update:modelValue", value: Entities[]) => void>(); const emit = defineEmits<(e: "update:modelValue", value: Entities[]) => void>();
@ -42,53 +42,46 @@ const emit = defineEmits<(e: "update:modelValue", value: Entities[]) => void>();
const selectedEntities = ref<Entities[]>([...props.modelValue]); const selectedEntities = ref<Entities[]>([...props.modelValue]);
const suggestedValues = ref<Entities[]>([...props.suggested]); const suggestedValues = ref<Entities[]>([...props.suggested]);
watch( watch(
() => [props.suggested, props.modelValue], () => [props.suggested, props.modelValue],
() => { () => {
const modelValue = props.modelValue ?? []; const modelValue = props.modelValue ?? [];
suggestedValues.value = props.suggested.filter( suggestedValues.value = props.suggested.filter((suggested: Entities) => {
(suggested: Entities) => { return !modelValue.some((selected: Entities) => {
return !modelValue.some((selected: Entities) => { if (suggested.type == "user_group" && selected.type == "user_group") {
if ( switch (selected.excludeKey) {
suggested.type == "user_group" && case "level":
selected.type == "user_group" return suggested.excludeKey === "level";
) { case "":
switch (selected.excludeKey) { return (
case "level": suggested.excludeKey === "" && suggested.id === selected.id
return suggested.excludeKey === "level"; );
case "": default:
return ( return false;
suggested.excludeKey === "" && }
suggested.id === selected.id } else {
); return (
default: suggested.type === selected.type && suggested.id === selected.id
return false; );
} }
} else { });
return ( });
suggested.type === selected.type && },
suggested.id === selected.id { immediate: true, deep: true },
);
}
});
},
);
},
{ immediate: true, deep: true },
); );
function addNewEntity({ entity }: { entity: Entities }) { function addNewEntity({ entity }: { entity: Entities }) {
selectedEntities.value.push(entity); selectedEntities.value.push(entity);
emit("update:modelValue", selectedEntities.value); emit("update:modelValue", selectedEntities.value);
} }
function removeEntity({ entity }: { entity: Entities }) { function removeEntity({ entity }: { entity: Entities }) {
const index = selectedEntities.value.findIndex( const index = selectedEntities.value.findIndex(
(selectedEntity) => selectedEntity === entity, (selectedEntity) => selectedEntity === entity,
); );
if (index !== -1) { if (index !== -1) {
selectedEntities.value.splice(index, 1); selectedEntities.value.splice(index, 1);
} }
emit("update:modelValue", selectedEntities.value); emit("update:modelValue", selectedEntities.value);
} }
</script> </script>

View File

@ -1,109 +1,97 @@
<template> <template>
<Teleport to="#header-ticket-main"> <Teleport to="#header-ticket-main">
<div class="container-xxl text-primary"> <div class="container-xxl text-primary">
<div class="row"> <div class="row">
<div class="col-md-6 col-sm-12 ps-md-5 ps-xxl-0"> <div class="col-md-6 col-sm-12 ps-md-5 ps-xxl-0">
<h1 v-if="ticket.currentMotive"> <h1 v-if="ticket.currentMotive">
#{{ ticket.id }} {{ ticket.currentMotive.label.fr }} #{{ ticket.id }} {{ ticket.currentMotive.label.fr }}
</h1> </h1>
<p class="chill-no-data-statement" v-else> <p class="chill-no-data-statement" v-else>
{{ trans(CHILL_TICKET_TICKET_BANNER_NO_MOTIVE) }} {{ trans(CHILL_TICKET_TICKET_BANNER_NO_MOTIVE) }}
</p> </p>
<h2 v-if="ticket.currentPersons.length"> <h2 v-if="ticket.currentPersons.length">
{{ {{ ticket.currentPersons.map((person) => person.text).join(", ") }}
ticket.currentPersons </h2>
.map((person) => person.text)
.join(", ")
}}
</h2>
</div>
<div class="col-md-6 col-sm-12">
<div class="d-flex justify-content-end">
<toggle-flags />
<span
class="badge text-bg-chill-green text-white"
style="font-size: 1rem"
v-if="isOpen"
>
{{ trans(CHILL_TICKET_TICKET_BANNER_OPEN) }}
</span>
<span
class="badge text-bg-chill-red text-white"
style="font-size: 1rem"
v-else
>
{{ trans(CHILL_TICKET_TICKET_BANNER_CLOSED) }}
</span>
</div>
<div class="d-flex justify-content-end">
<p class="created-at-timespan" v-if="ticket.createdAt">
{{
trans(CHILL_TICKET_TICKET_BANNER_SINCE, {
time: since,
})
}}
</p>
</div>
</div>
</div>
</div> </div>
</Teleport>
<Teleport to="#header-ticket-details"> <div class="col-md-6 col-sm-12">
<div class="container-xxl"> <div class="d-flex justify-content-end">
<div class="row justify-content-between"> <toggle-flags />
<div
class="col-md-4 col-sm-12 d-flex flex-column align-items-start" <span
> class="badge text-bg-chill-green text-white"
<h3 class="text-primary"> style="font-size: 1rem"
{{ trans(CHILL_TICKET_TICKET_BANNER_CALLER) }} v-if="isOpen"
</h3> >
<on-the-fly {{ trans(CHILL_TICKET_TICKET_BANNER_OPEN) }}
v-if="ticket.caller" </span>
:key="ticket.caller.id" <span
:type="ticket.caller.type" class="badge text-bg-chill-red text-white"
:id="ticket.caller.id" style="font-size: 1rem"
:buttonText="ticket.caller.textAge" v-else
:displayBadge="'true' === 'true'" >
action="show" {{ trans(CHILL_TICKET_TICKET_BANNER_CLOSED) }}
></on-the-fly> </span>
</div> </div>
<div <div class="d-flex justify-content-end">
class="col-md-4 col-sm-12 d-flex flex-column align-items-start" <p class="created-at-timespan" v-if="ticket.createdAt">
> {{
<h3 class="text-primary"> trans(CHILL_TICKET_TICKET_BANNER_SINCE, {
{{ trans(CHILL_TICKET_TICKET_BANNER_CONCERNED_USAGER) }} time: since,
</h3> })
<on-the-fly }}
v-for="person in ticket.currentPersons" </p>
:key="person.id" </div>
:type="person.type"
:id="person.id"
:buttonText="person.textAge"
:displayBadge="'true' === 'true'"
action="show"
></on-the-fly>
</div>
<div
class="col-md-4 col-sm-12 d-flex flex-column align-items-start"
>
<h3 class="text-primary">
{{ trans(CHILL_TICKET_TICKET_BANNER_SPEAKER) }}
</h3>
<addressee-component
:addressees="ticket.currentAddressees"
/>
</div>
</div>
</div> </div>
</Teleport> </div>
</div>
</Teleport>
<Teleport to="#header-ticket-details">
<div class="container-xxl">
<div class="row justify-content-between">
<div class="col-md-4 col-sm-12 d-flex flex-column align-items-start">
<h3 class="text-primary">
{{ trans(CHILL_TICKET_TICKET_BANNER_CALLER) }}
</h3>
<on-the-fly
v-if="ticket.caller"
:key="ticket.caller.id"
:type="ticket.caller.type"
:id="ticket.caller.id"
:buttonText="ticket.caller.text"
:displayBadge="'true' === 'true'"
action="show"
></on-the-fly>
</div>
<div class="col-md-4 col-sm-12 d-flex flex-column align-items-start">
<h3 class="text-primary">
{{ trans(CHILL_TICKET_TICKET_BANNER_CONCERNED_USAGER) }}
</h3>
<on-the-fly
v-for="person in ticket.currentPersons"
:key="person.id"
:type="person.type"
:id="person.id"
:buttonText="person.textAge"
:displayBadge="'true' === 'true'"
action="show"
></on-the-fly>
</div>
<div class="col-md-4 col-sm-12 d-flex flex-column align-items-start">
<h3 class="text-primary">
{{ trans(CHILL_TICKET_TICKET_BANNER_SPEAKER) }}
</h3>
<addressee-component :addressees="ticket.currentAddressees" />
</div>
</div>
</div>
</Teleport>
</template> </template>
<style lang="scss"> <style lang="scss">
.created-at-timespan { .created-at-timespan {
font-weight: 600; font-weight: 600;
font-variant: all-petite-caps; font-variant: all-petite-caps;
} }
</style> </style>
@ -121,26 +109,26 @@ import { ISOToDatetime } from "../../../../../../../ChillMainBundle/Resources/pu
// Translations // Translations
import { import {
trans, trans,
CHILL_TICKET_TICKET_BANNER_NO_MOTIVE, CHILL_TICKET_TICKET_BANNER_NO_MOTIVE,
CHILL_TICKET_TICKET_BANNER_OPEN, CHILL_TICKET_TICKET_BANNER_OPEN,
CHILL_TICKET_TICKET_BANNER_CLOSED, CHILL_TICKET_TICKET_BANNER_CLOSED,
CHILL_TICKET_TICKET_BANNER_SINCE, CHILL_TICKET_TICKET_BANNER_SINCE,
CHILL_TICKET_TICKET_BANNER_CONCERNED_USAGER, CHILL_TICKET_TICKET_BANNER_CONCERNED_USAGER,
CHILL_TICKET_TICKET_BANNER_SPEAKER, CHILL_TICKET_TICKET_BANNER_SPEAKER,
CHILL_TICKET_TICKET_BANNER_DAYS, CHILL_TICKET_TICKET_BANNER_DAYS,
CHILL_TICKET_TICKET_BANNER_HOURS, CHILL_TICKET_TICKET_BANNER_HOURS,
CHILL_TICKET_TICKET_BANNER_MINUTES, CHILL_TICKET_TICKET_BANNER_MINUTES,
CHILL_TICKET_TICKET_BANNER_SECONDS, CHILL_TICKET_TICKET_BANNER_SECONDS,
CHILL_TICKET_TICKET_BANNER_AND, CHILL_TICKET_TICKET_BANNER_AND,
CHILL_TICKET_TICKET_BANNER_CALLER, CHILL_TICKET_TICKET_BANNER_CALLER,
} from "translator"; } from "translator";
// Store // Store
import { useStore } from "vuex"; import { useStore } from "vuex";
const props = defineProps<{ const props = defineProps<{
ticket: Ticket; ticket: Ticket;
}>(); }>();
const store = useStore(); const store = useStore();
@ -148,59 +136,55 @@ const today = ref(new Date());
const createdAt = ref(props.ticket.createdAt); const createdAt = ref(props.ticket.createdAt);
setInterval(() => { setInterval(() => {
today.value = new Date(); today.value = new Date();
}, 5000); }, 5000);
const isOpen = computed(() => store.getters.isOpen); const isOpen = computed(() => store.getters.isOpen);
const since = computed(() => { const since = computed(() => {
if (createdAt.value == null) { if (createdAt.value == null) {
return ""; return "";
} }
const date = ISOToDatetime(createdAt.value.datetime); const date = ISOToDatetime(createdAt.value.datetime);
if (date == null) { if (date == null) {
return ""; return "";
} }
const timeDiff = Math.abs(today.value.getTime() - date.getTime()); const timeDiff = Math.abs(today.value.getTime() - date.getTime());
const daysDiff = Math.floor(timeDiff / (1000 * 3600 * 24)); const daysDiff = Math.floor(timeDiff / (1000 * 3600 * 24));
const hoursDiff = Math.floor( const hoursDiff = Math.floor((timeDiff % (1000 * 3600 * 24)) / (1000 * 3600));
(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 }),
); );
const minutesDiff = Math.floor((timeDiff % (1000 * 3600)) / (1000 * 60)); }
const secondsDiff = Math.floor((timeDiff % (1000 * 60)) / 1000); if (parts.length === 0) {
return trans(CHILL_TICKET_TICKET_BANNER_SECONDS, {
// On construit la liste des parties à afficher count: secondsDiff,
const parts: string[] = []; });
if (daysDiff > 0) { }
parts.push(trans(CHILL_TICKET_TICKET_BANNER_DAYS, { count: daysDiff })); if (parts.length > 1) {
} const last = parts.pop();
if (hoursDiff > 0 || daysDiff > 0) { return (
parts.push( parts.join(", ") +
trans(CHILL_TICKET_TICKET_BANNER_HOURS, { count: hoursDiff }), " " +
); trans(CHILL_TICKET_TICKET_BANNER_AND) +
} " " +
if (minutesDiff > 0 || hoursDiff > 0 || daysDiff > 0) { last
parts.push( );
trans(CHILL_TICKET_TICKET_BANNER_MINUTES, { count: minutesDiff }), }
); return parts[0];
}
if (parts.length === 0) {
return trans(CHILL_TICKET_TICKET_BANNER_SECONDS, {
count: secondsDiff,
});
}
if (parts.length > 1) {
const last = parts.pop();
return (
parts.join(", ") +
" " +
trans(CHILL_TICKET_TICKET_BANNER_AND) +
" " +
last
);
}
return parts[0];
}); });
</script> </script>

View File

@ -1,16 +1,16 @@
<template> <template>
<pick-entity <pick-entity
uniqid="ticket-person-selector" uniqid="ticket-person-selector"
:types="['person', 'third_party']" :types="['person', 'thirdparty']"
:picked="selectedEntity ? [selectedEntity] : []" :picked="selectedEntity ? [selectedEntity] : []"
:suggested="suggestedValues" :suggested="suggestedValues"
:multiple="false" :multiple="false"
:removable-if-set="true" :removable-if-set="true"
:display-picked="true" :display-picked="true"
:label="trans(CHILL_TICKET_TICKET_SET_PERSONS_CALLER_LABEL)" :label="trans(CHILL_TICKET_TICKET_SET_PERSONS_CALLER_LABEL)"
@add-new-entity="addNewEntity" @add-new-entity="addNewEntity"
@remove-entity="removeEntity" @remove-entity="removeEntity"
/> />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -24,62 +24,62 @@ import { Entities } from "ChillPersonAssets/types";
// Translations // Translations
import { import {
trans, trans,
CHILL_TICKET_TICKET_SET_PERSONS_CALLER_LABEL, CHILL_TICKET_TICKET_SET_PERSONS_CALLER_LABEL,
} from "translator"; } from "translator";
const props = defineProps<{ const props = defineProps<{
modelValue: Entities | null; modelValue: Entities | null;
suggested: Entities[]; suggested: Entities[];
}>(); }>();
const emit = const emit =
defineEmits<(event: "update:modelValue", value: Entities | null) => void>(); defineEmits<(event: "update:modelValue", value: Entities | null) => void>();
const selectedEntity = ref<Entities | null>(props.modelValue); const selectedEntity = ref<Entities | null>(props.modelValue);
const suggestedValues = ref<Entities[]>([...props.suggested]); const suggestedValues = ref<Entities[]>([...props.suggested]);
watch( watch(
() => [props.suggested, props.modelValue], () => [props.suggested, props.modelValue],
() => { () => {
suggestedValues.value = props.suggested.filter( suggestedValues.value = props.suggested.filter(
(suggested: Entities) => (suggested: Entities) =>
suggested.id === selectedEntity.value?.id && suggested.id === selectedEntity.value?.id &&
suggested.type === selectedEntity.value?.type, suggested.type === selectedEntity.value?.type,
); );
}, },
{ immediate: true, deep: true }, { immediate: true, deep: true },
); );
function addNewEntity({ entity }: { entity: Entities }) { function addNewEntity({ entity }: { entity: Entities }) {
selectedEntity.value = entity; selectedEntity.value = entity;
emit("update:modelValue", selectedEntity.value); emit("update:modelValue", selectedEntity.value);
} }
function removeEntity() { function removeEntity() {
selectedEntity.value = null; selectedEntity.value = null;
emit("update:modelValue", null); emit("update:modelValue", null);
} }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
ul.person-list { ul.person-list {
list-style-type: none; list-style-type: none;
& > li { & > li {
display: inline-block; display: inline-block;
border: 1px solid transparent; border: 1px solid transparent;
border-radius: 6px; border-radius: 6px;
button.remove-person { button.remove-person {
opacity: 10%; opacity: 10%;
}
} }
}
& > li:hover { & > li:hover {
border: 1px solid white; border: 1px solid white;
button.remove-person { button.remove-person {
opacity: 100%; opacity: 100%;
}
} }
}
} }
</style> </style>

View File

@ -1,79 +1,75 @@
<template> <template>
<div <div
class="card my-2 bg-light" class="card my-2 bg-light"
v-for="history_line in history.filter( v-for="history_line in history.filter(
(line) => line.event_type != 'add_person', (line) => line.event_type != 'add_person',
)" )"
:key="history.indexOf(history_line)" :key="history.indexOf(history_line)"
> >
<div class="card-header"> <div class="card-header">
<div <div
class="history-header d-flex align-items-center justify-content-between" class="history-header d-flex align-items-center justify-content-between"
> >
<div class="d-flex align-items-center fw-bold"> <div class="d-flex align-items-center fw-bold">
<i <i :class="`${actionIcons[history_line.event_type]} me-1`"></i>
:class="`${actionIcons[history_line.event_type]} me-1`" <span>{{ explainSentence(history_line) }}</span>
></i> <TicketHistoryStateComponent
<span>{{ explainSentence(history_line) }}</span> :new_state="history_line.data.new_state"
<TicketHistoryStateComponent v-if="history_line.event_type == 'state_change'"
:new_state="history_line.data.new_state" />
v-if="history_line.event_type == 'state_change'" <TicketHistoryEmergencyComponent
/> v-if="history_line.event_type == 'emergency_change'"
<TicketHistoryEmergencyComponent :new_emergency="history_line.data.new_emergency"
v-if="history_line.event_type == 'emergency_change'" />
:new_emergency="history_line.data.new_emergency"
/>
</div>
<div>
<span class="badge-user">
<user-render-box-badge
:user="history_line.by"
></user-render-box-badge>
</span>
<span class="fst-italic mx-2">
{{ formatDate(history_line.at) }}
</span>
</div>
</div>
</div> </div>
<div <div>
class="card-body row" <span class="badge-user">
v-if=" <user-render-box-badge
!['state_change', 'emergency_change'].includes( :user="history_line.by"
history_line.event_type, ></user-render-box-badge>
) </span>
" <span class="fst-italic mx-2">
> {{ formatDate(history_line.at) }}
<ticket-history-person-component </span>
:persons="history_line.data.persons"
v-if="history_line.event_type == 'persons_state'"
/>
<ticket-history-person-component
:persons="
history_line.data.new_caller
? [history_line.data.new_caller]
: []
"
v-if="history_line.event_type == 'set_caller'"
/>
<ticket-history-motive-component
:motiveHistory="history_line.data"
v-else-if="history_line.event_type == 'set_motive'"
/>
<ticket-history-comment-component
:commentHistory="history_line.data"
v-else-if="history_line.event_type == 'add_comment'"
/>
<ticket-history-addressee-component
:addresseeState="history_line.data"
v-else-if="history_line.event_type == 'addressees_state'"
/>
<ticket-history-create-component
:by="history_line.by"
v-else-if="history_line.event_type == 'create_ticket'"
/>
</div> </div>
</div>
</div> </div>
<div
class="card-body row"
v-if="
!['state_change', 'emergency_change'].includes(history_line.event_type)
"
>
<ticket-history-person-component
:entities="history_line.data.persons"
v-if="history_line.event_type == 'persons_state'"
/>
<ticket-history-person-component
:entities="
history_line.data.new_caller
? ([history_line.data.new_caller] as Person[] | Thirdparty[])
: []
"
v-if="history_line.event_type == 'set_caller'"
/>
<ticket-history-motive-component
:motiveHistory="history_line.data"
v-else-if="history_line.event_type == 'set_motive'"
/>
<ticket-history-comment-component
:commentHistory="history_line.data"
v-else-if="history_line.event_type == 'add_comment'"
/>
<ticket-history-addressee-component
:addresseeState="history_line.data"
v-else-if="history_line.event_type == 'addressees_state'"
/>
<ticket-history-create-component
:by="history_line.by"
v-else-if="history_line.event_type == 'create_ticket'"
/>
</div>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { ref } from "vue";
@ -82,6 +78,8 @@ import { useStore } from "vuex";
// Types // Types
import { DateTime } from "../../../../../../../ChillMainBundle/Resources/public/types"; import { DateTime } from "../../../../../../../ChillMainBundle/Resources/public/types";
import { TicketHistoryLine } from "../../../types"; import { TicketHistoryLine } from "../../../types";
import { Person } from "ChillPersonAssets/types";
import { Thirdparty } from "src/Bundle/ChillThirdPartyBundle/Resources/public/types";
// Components // Components
import TicketHistoryPersonComponent from "./TicketHistoryPersonComponent.vue"; import TicketHistoryPersonComponent from "./TicketHistoryPersonComponent.vue";
@ -99,15 +97,15 @@ import { ISOToDatetime } from "../../../../../../../ChillMainBundle/Resources/pu
// Translations // Translations
import { import {
trans, trans,
CHILL_TICKET_TICKET_HISTORY_ADD_COMMENT, CHILL_TICKET_TICKET_HISTORY_ADD_COMMENT,
CHILL_TICKET_TICKET_HISTORY_ADDRESSEES_STATE, CHILL_TICKET_TICKET_HISTORY_ADDRESSEES_STATE,
CHILL_TICKET_TICKET_HISTORY_PERSONS_STATE, CHILL_TICKET_TICKET_HISTORY_PERSONS_STATE,
CHILL_TICKET_TICKET_HISTORY_SET_MOTIVE, CHILL_TICKET_TICKET_HISTORY_SET_MOTIVE,
CHILL_TICKET_TICKET_HISTORY_CREATE_TICKET, CHILL_TICKET_TICKET_HISTORY_CREATE_TICKET,
CHILL_TICKET_TICKET_HISTORY_STATE_CHANGE, CHILL_TICKET_TICKET_HISTORY_STATE_CHANGE,
CHILL_TICKET_TICKET_HISTORY_EMERGENCY_CHANGE, CHILL_TICKET_TICKET_HISTORY_EMERGENCY_CHANGE,
CHILL_TICKET_TICKET_HISTORY_SET_CALLER, CHILL_TICKET_TICKET_HISTORY_SET_CALLER,
} from "translator"; } from "translator";
defineProps<{ history: TicketHistoryLine[] }>(); defineProps<{ history: TicketHistoryLine[] }>();
@ -116,36 +114,36 @@ const store = useStore();
const actionIcons = ref(store.getters.getActionIcons); const actionIcons = ref(store.getters.getActionIcons);
function explainSentence(history: TicketHistoryLine): string { function explainSentence(history: TicketHistoryLine): string {
switch (history.event_type) { switch (history.event_type) {
case "add_comment": case "add_comment":
return trans(CHILL_TICKET_TICKET_HISTORY_ADD_COMMENT); return trans(CHILL_TICKET_TICKET_HISTORY_ADD_COMMENT);
case "addressees_state": case "addressees_state":
return trans(CHILL_TICKET_TICKET_HISTORY_ADDRESSEES_STATE); return trans(CHILL_TICKET_TICKET_HISTORY_ADDRESSEES_STATE);
case "persons_state": case "persons_state":
return trans(CHILL_TICKET_TICKET_HISTORY_PERSONS_STATE); return trans(CHILL_TICKET_TICKET_HISTORY_PERSONS_STATE);
case "set_motive": case "set_motive":
return trans(CHILL_TICKET_TICKET_HISTORY_SET_MOTIVE); return trans(CHILL_TICKET_TICKET_HISTORY_SET_MOTIVE);
case "create_ticket": case "create_ticket":
return trans(CHILL_TICKET_TICKET_HISTORY_CREATE_TICKET); return trans(CHILL_TICKET_TICKET_HISTORY_CREATE_TICKET);
case "state_change": case "state_change":
return trans(CHILL_TICKET_TICKET_HISTORY_STATE_CHANGE); return trans(CHILL_TICKET_TICKET_HISTORY_STATE_CHANGE);
case "emergency_change": case "emergency_change":
return trans(CHILL_TICKET_TICKET_HISTORY_EMERGENCY_CHANGE); return trans(CHILL_TICKET_TICKET_HISTORY_EMERGENCY_CHANGE);
case "set_caller": case "set_caller":
return trans(CHILL_TICKET_TICKET_HISTORY_SET_CALLER); return trans(CHILL_TICKET_TICKET_HISTORY_SET_CALLER);
default: default:
return ""; return "";
} }
} }
function formatDate(d: DateTime): string { function formatDate(d: DateTime): string {
const date = ISOToDatetime(d.datetime); const date = ISOToDatetime(d.datetime);
if (date === null) { if (date === null) {
return ""; return "";
} }
const month = date.toLocaleString("default", { month: "long" }); const month = date.toLocaleString("default", { month: "long" });
return `${date.getDate()} ${month} ${date.getFullYear()}, ${date.toLocaleTimeString()}`; return `${date.getDate()} ${month} ${date.getFullYear()}, ${date.toLocaleTimeString()}`;
} }
</script> </script>

View File

@ -1,18 +1,18 @@
<template> <template>
<div class="col-12"> <div class="col-12">
<ul class="persons-list" v-if="persons.length > 0"> <ul class="persons-list" v-if="entities.length > 0">
<li v-for="person in persons" :key="person.id"> <li v-for="entity in entities" :key="entity.text">
<on-the-fly <on-the-fly
:type="person.type" :type="entity.type"
:id="person.id" :id="entity.id"
:buttonText="person.textAge" :buttonText="entity.text"
:displayBadge="true" :displayBadge="true"
action="show" action="show"
></on-the-fly> ></on-the-fly>
</li> </li>
</ul> </ul>
<div v-else class="text-muted">Aucune personne concernée</div> <div v-else class="text-muted">Aucune personne concernée</div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -20,17 +20,18 @@ import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
// Types // Types
import { Person } from "ChillPersonAssets/types"; import { Person } from "ChillPersonAssets/types";
import { Thirdparty } from "src/Bundle/ChillThirdPartyBundle/Resources/public/types";
defineProps<{ persons: Person[] }>(); defineProps<{ entities: Person[] | Thirdparty[] }>();
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
ul.persons-list { ul.persons-list {
list-style-type: none; list-style-type: none;
& > li { & > li {
display: inline-block; display: inline-block;
margin: 0 0.15rem; margin: 0 0.15rem;
} }
} }
</style> </style>