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

View File

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

View File

@@ -1,109 +1,97 @@
<template>
<Teleport to="#header-ticket-main">
<div class="container-xxl text-primary">
<div class="row">
<div class="col-md-6 col-sm-12 ps-md-5 ps-xxl-0">
<h1 v-if="ticket.currentMotive">
#{{ ticket.id }} {{ ticket.currentMotive.label.fr }}
</h1>
<p class="chill-no-data-statement" v-else>
{{ trans(CHILL_TICKET_TICKET_BANNER_NO_MOTIVE) }}
</p>
<h2 v-if="ticket.currentPersons.length">
{{
ticket.currentPersons
.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>
<Teleport to="#header-ticket-main">
<div class="container-xxl text-primary">
<div class="row">
<div class="col-md-6 col-sm-12 ps-md-5 ps-xxl-0">
<h1 v-if="ticket.currentMotive">
#{{ ticket.id }} {{ ticket.currentMotive.label.fr }}
</h1>
<p class="chill-no-data-statement" v-else>
{{ trans(CHILL_TICKET_TICKET_BANNER_NO_MOTIVE) }}
</p>
<h2 v-if="ticket.currentPersons.length">
{{ ticket.currentPersons.map((person) => person.text).join(", ") }}
</h2>
</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.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_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 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>
</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>
<style lang="scss">
.created-at-timespan {
font-weight: 600;
font-variant: all-petite-caps;
font-weight: 600;
font-variant: all-petite-caps;
}
</style>
@@ -121,26 +109,26 @@ import { ISOToDatetime } from "../../../../../../../ChillMainBundle/Resources/pu
// Translations
import {
trans,
CHILL_TICKET_TICKET_BANNER_NO_MOTIVE,
CHILL_TICKET_TICKET_BANNER_OPEN,
CHILL_TICKET_TICKET_BANNER_CLOSED,
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,
CHILL_TICKET_TICKET_BANNER_CALLER,
trans,
CHILL_TICKET_TICKET_BANNER_NO_MOTIVE,
CHILL_TICKET_TICKET_BANNER_OPEN,
CHILL_TICKET_TICKET_BANNER_CLOSED,
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,
CHILL_TICKET_TICKET_BANNER_CALLER,
} from "translator";
// Store
import { useStore } from "vuex";
const props = defineProps<{
ticket: Ticket;
ticket: Ticket;
}>();
const store = useStore();
@@ -148,59 +136,55 @@ const today = ref(new Date());
const createdAt = ref(props.ticket.createdAt);
setInterval(() => {
today.value = new Date();
today.value = new Date();
}, 5000);
const isOpen = computed(() => store.getters.isOpen);
const since = computed(() => {
if (createdAt.value == null) {
return "";
}
const date = ISOToDatetime(createdAt.value.datetime);
if (createdAt.value == null) {
return "";
}
const date = ISOToDatetime(createdAt.value.datetime);
if (date == null) {
return "";
}
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 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 }),
);
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,
});
}
if (parts.length > 1) {
const last = parts.pop();
return (
parts.join(", ") +
" " +
trans(CHILL_TICKET_TICKET_BANNER_AND) +
" " +
last
);
}
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>

View File

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

View File

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

View File

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