mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-09-28 01:25:00 +00:00
Merge remote-tracking branch 'origin/ticket-app-master' into ticket-app-master
This commit is contained in:
@@ -107,3 +107,15 @@ export interface Ticket {
|
||||
createdAt: DateTime | null;
|
||||
updatedBy: User | null;
|
||||
}
|
||||
|
||||
export interface addNewPersons {
|
||||
selected: Selected[];
|
||||
modal: Modal;
|
||||
}
|
||||
export interface Modal {
|
||||
showModal: boolean;
|
||||
modalDialogClass: string;
|
||||
}
|
||||
export interface Selected {
|
||||
result: User;
|
||||
}
|
||||
|
@@ -6,13 +6,13 @@
|
||||
</div>
|
||||
<action-toolbar-component />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, inject, onMounted, ref } from "vue";
|
||||
<script setup lang="ts">
|
||||
import { useToast } from "vue-toast-notification";
|
||||
import { computed, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
|
||||
// Types
|
||||
import { Motive, Ticket } from "../../types";
|
||||
import { Ticket } from "../../types";
|
||||
|
||||
// Components
|
||||
import TicketSelectorComponent from "./components/TicketSelectorComponent.vue";
|
||||
@@ -20,43 +20,23 @@ import TicketHistoryListComponent from "./components/TicketHistoryListComponent.
|
||||
import ActionToolbarComponent from "./components/ActionToolbarComponent.vue";
|
||||
import BannerComponent from "./components/BannerComponent.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "App",
|
||||
components: {
|
||||
TicketSelectorComponent,
|
||||
TicketHistoryListComponent,
|
||||
ActionToolbarComponent,
|
||||
BannerComponent,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore();
|
||||
const toast = inject("toast") as any;
|
||||
const store = useStore();
|
||||
const toast = useToast();
|
||||
|
||||
store.commit("setTicket", JSON.parse(window.initialTicket) as Ticket);
|
||||
store.commit("setTicket", JSON.parse(window.initialTicket) as Ticket);
|
||||
|
||||
const motives = computed(() => store.getters.getMotives as Motive[]);
|
||||
const ticket = computed(() => store.getters.getTicket as Ticket);
|
||||
const ticket = computed(() => store.getters.getTicket as Ticket);
|
||||
|
||||
const ticketHistory = computed(
|
||||
() => store.getters.getDistinctAddressesHistory,
|
||||
);
|
||||
const ticketHistory = computed(() => store.getters.getDistinctAddressesHistory);
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
await store.dispatch("fetchMotives");
|
||||
await store.dispatch("fetchUserGroups");
|
||||
await store.dispatch("fetchUsers");
|
||||
} catch (error) {
|
||||
toast.error(error);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
ticketHistory,
|
||||
motives,
|
||||
ticket,
|
||||
};
|
||||
},
|
||||
onMounted(async () => {
|
||||
try {
|
||||
await store.dispatch("fetchMotives");
|
||||
await store.dispatch("fetchUserGroups");
|
||||
await store.dispatch("fetchUsers");
|
||||
} catch (error) {
|
||||
toast.error(error as string);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<div class="tab-content p-2">
|
||||
<div>
|
||||
<label class="col-form-label">
|
||||
{{ $t(`${activeTab}.title`) }}
|
||||
{{ activeTabTitle }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -36,12 +36,20 @@
|
||||
@click="activeTab = ''"
|
||||
class="btn btn-cancel"
|
||||
>
|
||||
{{ $t("ticket.cancel") }}
|
||||
{{
|
||||
trans(
|
||||
CHILL_TICKET_TICKET_ACTIONS_TOOLBAR_CANCEL,
|
||||
)
|
||||
}}
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button class="btn btn-save" type="submit">
|
||||
{{ $t("ticket.save") }}
|
||||
{{
|
||||
trans(
|
||||
CHILL_TICKET_TICKET_ACTIONS_TOOLBAR_SAVE,
|
||||
)
|
||||
}}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -78,7 +86,7 @@
|
||||
"
|
||||
>
|
||||
<i :class="actionIcons['set_motive']"></i>
|
||||
{{ $t("set_motive.title") }}
|
||||
{{ trans(CHILL_TICKET_TICKET_SET_MOTIVE_TITLE) }}
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item p-2">
|
||||
@@ -96,7 +104,7 @@
|
||||
"
|
||||
>
|
||||
<i :class="actionIcons['add_comment']"></i>
|
||||
{{ $t("add_comment.title") }}
|
||||
{{ trans(CHILL_TICKET_TICKET_ADD_COMMENT_TITLE) }}
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item p-2">
|
||||
@@ -114,7 +122,7 @@
|
||||
"
|
||||
>
|
||||
<i :class="actionIcons['addressees_state']"></i>
|
||||
{{ $t("add_addressee.title") }}
|
||||
{{ trans(CHILL_TICKET_TICKET_ADD_ADDRESSEE_TITLE) }}
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item p-2">
|
||||
@@ -132,7 +140,7 @@
|
||||
"
|
||||
>
|
||||
<i :class="actionIcons['set_persons']"></i>
|
||||
Patients concernés
|
||||
{{ trans(CHILL_TICKET_TICKET_SET_PERSONS_TITLE) }}
|
||||
</button>
|
||||
</li>
|
||||
|
||||
@@ -143,7 +151,7 @@
|
||||
@click="handleClick()"
|
||||
>
|
||||
<i class="fa fa-bolt"></i>
|
||||
{{ $t("ticket.close") }}
|
||||
{{ trans(CHILL_TICKET_TICKET_ACTIONS_TOOLBAR_CLOSE) }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -151,10 +159,34 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, inject, ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import { useToast } from "vue-toast-notification";
|
||||
|
||||
// Component
|
||||
import MotiveSelectorComponent from "./MotiveSelectorComponent.vue";
|
||||
import AddresseeSelectorComponent from "./AddresseeSelectorComponent.vue";
|
||||
import AddCommentComponent from "./AddCommentComponent.vue";
|
||||
import PersonsSelectorComponent from "./PersonsSelectorComponent.vue";
|
||||
|
||||
// Translations
|
||||
import {
|
||||
trans,
|
||||
CHILL_TICKET_TICKET_ADD_ADDRESSEE_TITLE,
|
||||
CHILL_TICKET_TICKET_ADD_ADDRESSEE_ERROR,
|
||||
CHILL_TICKET_TICKET_ADD_ADDRESSEE_SUCCESS,
|
||||
CHILL_TICKET_TICKET_ADD_COMMENT_TITLE,
|
||||
CHILL_TICKET_TICKET_ADD_COMMENT_ERROR,
|
||||
CHILL_TICKET_TICKET_ADD_COMMENT_SUCCESS,
|
||||
CHILL_TICKET_TICKET_SET_MOTIVE_TITLE,
|
||||
CHILL_TICKET_TICKET_SET_MOTIVE_ERROR,
|
||||
CHILL_TICKET_TICKET_SET_MOTIVE_SUCCESS,
|
||||
CHILL_TICKET_TICKET_SET_PERSONS_TITLE,
|
||||
CHILL_TICKET_TICKET_ACTIONS_TOOLBAR_CLOSE,
|
||||
CHILL_TICKET_TICKET_ACTIONS_TOOLBAR_CANCEL,
|
||||
CHILL_TICKET_TICKET_ACTIONS_TOOLBAR_SAVE,
|
||||
} from "translator";
|
||||
|
||||
// Types
|
||||
import {
|
||||
@@ -164,140 +196,118 @@ import {
|
||||
} from "../../../../../../../ChillMainBundle/Resources/public/types";
|
||||
import { Comment, Motive, Ticket } from "../../../types";
|
||||
|
||||
// Component
|
||||
import MotiveSelectorComponent from "./MotiveSelectorComponent.vue";
|
||||
import AddresseeSelectorComponent from "./AddresseeSelectorComponent.vue";
|
||||
import AddCommentComponent from "./AddCommentComponent.vue";
|
||||
import PersonsSelectorComponent from "./PersonsSelectorComponent.vue";
|
||||
const store = useStore();
|
||||
const toast = useToast();
|
||||
|
||||
export default defineComponent({
|
||||
name: "ActionToolbarComponent",
|
||||
components: {
|
||||
PersonsSelectorComponent,
|
||||
AddCommentComponent,
|
||||
MotiveSelectorComponent,
|
||||
AddresseeSelectorComponent,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore();
|
||||
const { t } = useI18n();
|
||||
const toast = inject("toast") as any;
|
||||
const activeTab = ref(
|
||||
"" as
|
||||
| ""
|
||||
| "add_comment"
|
||||
| "set_motive"
|
||||
| "add_addressee"
|
||||
| "set_persons",
|
||||
);
|
||||
const activeTab = ref(
|
||||
"" as "" | "add_comment" | "set_motive" | "add_addressee" | "set_persons",
|
||||
);
|
||||
|
||||
const ticket = computed(() => store.getters.getTicket as Ticket);
|
||||
const motives = computed(() => store.getters.getMotives as Motive[]);
|
||||
const userGroups = computed(
|
||||
() => store.getters.getUserGroups as UserGroup[],
|
||||
);
|
||||
const users = computed(() => store.getters.getUsers as User[]);
|
||||
|
||||
const hasReturnPath = computed((): boolean => {
|
||||
const params = new URL(document.location.toString()).searchParams;
|
||||
return params.has("returnPath");
|
||||
});
|
||||
|
||||
const returnPath = computed((): string => {
|
||||
const params = new URL(document.location.toString()).searchParams;
|
||||
const returnPath = params.get("returnPath");
|
||||
|
||||
if (null === returnPath) {
|
||||
throw new Error(
|
||||
"there isn't any returnPath, please check the existence before",
|
||||
);
|
||||
}
|
||||
|
||||
return returnPath;
|
||||
});
|
||||
|
||||
const motive = ref(
|
||||
ticket.value.currentMotive
|
||||
? ticket.value.currentMotive
|
||||
: ({} as Motive),
|
||||
);
|
||||
const content = ref("" as Comment["content"]);
|
||||
const addressees = ref(
|
||||
ticket.value.currentAddressees as UserGroupOrUser[],
|
||||
);
|
||||
|
||||
async function submitAction() {
|
||||
try {
|
||||
switch (activeTab.value) {
|
||||
case "add_comment":
|
||||
if (!content.value) {
|
||||
toast.error(t("add_comment.error"));
|
||||
} else {
|
||||
await store.dispatch("createComment", {
|
||||
ticketId: ticket.value.id,
|
||||
content: content.value,
|
||||
});
|
||||
content.value = "";
|
||||
activeTab.value = "";
|
||||
toast.success(t("add_comment.success"));
|
||||
}
|
||||
break;
|
||||
case "set_motive":
|
||||
if (!motive.value.id) {
|
||||
toast.error(t("set_motive.error"));
|
||||
} else {
|
||||
await store.dispatch("createMotive", {
|
||||
ticketId: ticket.value.id,
|
||||
motive: motive.value,
|
||||
});
|
||||
activeTab.value = "";
|
||||
toast.success(t("set_motive.success"));
|
||||
}
|
||||
break;
|
||||
case "add_addressee":
|
||||
if (!addressees.value.length) {
|
||||
toast.error(t("add_addressee.error"));
|
||||
} else {
|
||||
await store.dispatch("setAdressees", {
|
||||
ticketId: ticket.value.id,
|
||||
addressees: addressees.value,
|
||||
});
|
||||
activeTab.value = "";
|
||||
toast.success(t("add_addressee.success"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
function handleClick() {
|
||||
alert("Sera disponible plus tard");
|
||||
}
|
||||
|
||||
const closeAllActions = function () {
|
||||
activeTab.value = "";
|
||||
};
|
||||
|
||||
return {
|
||||
actionIcons: ref(store.getters.getActionIcons),
|
||||
activeTab,
|
||||
ticket,
|
||||
motives,
|
||||
motive,
|
||||
userGroups,
|
||||
addressees,
|
||||
users,
|
||||
content,
|
||||
submitAction,
|
||||
handleClick,
|
||||
hasReturnPath,
|
||||
returnPath,
|
||||
closeAllActions,
|
||||
};
|
||||
},
|
||||
const activeTabTitle = computed((): string => {
|
||||
switch (activeTab.value) {
|
||||
case "add_comment":
|
||||
return trans(CHILL_TICKET_TICKET_ADD_COMMENT_TITLE);
|
||||
case "set_motive":
|
||||
return trans(CHILL_TICKET_TICKET_SET_MOTIVE_TITLE);
|
||||
case "add_addressee":
|
||||
return trans(CHILL_TICKET_TICKET_ADD_ADDRESSEE_TITLE);
|
||||
case "set_persons":
|
||||
return trans(CHILL_TICKET_TICKET_SET_PERSONS_TITLE);
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
});
|
||||
|
||||
const ticket = computed(() => store.getters.getTicket as Ticket);
|
||||
const motives = computed(() => store.getters.getMotives as Motive[]);
|
||||
const userGroups = computed(() => store.getters.getUserGroups as UserGroup[]);
|
||||
const users = computed(() => store.getters.getUsers as User[]);
|
||||
|
||||
const hasReturnPath = computed((): boolean => {
|
||||
const params = new URL(document.location.toString()).searchParams;
|
||||
return params.has("returnPath");
|
||||
});
|
||||
|
||||
const returnPath = computed((): string => {
|
||||
const params = new URL(document.location.toString()).searchParams;
|
||||
const returnPath = params.get("returnPath");
|
||||
|
||||
if (null === returnPath) {
|
||||
throw new Error(
|
||||
"there isn't any returnPath, please check the existence before",
|
||||
);
|
||||
}
|
||||
|
||||
return returnPath;
|
||||
});
|
||||
|
||||
const motive = ref(
|
||||
ticket.value.currentMotive ? ticket.value.currentMotive : ({} as Motive),
|
||||
);
|
||||
const content = ref("" as Comment["content"]);
|
||||
const addressees = ref(ticket.value.currentAddressees as UserGroupOrUser[]);
|
||||
|
||||
async function submitAction() {
|
||||
try {
|
||||
switch (activeTab.value) {
|
||||
case "add_comment":
|
||||
if (!content.value) {
|
||||
toast.error(trans(CHILL_TICKET_TICKET_ADD_COMMENT_ERROR));
|
||||
} else {
|
||||
await store.dispatch("createComment", {
|
||||
ticketId: ticket.value.id,
|
||||
content: content.value,
|
||||
});
|
||||
content.value = "";
|
||||
activeTab.value = "";
|
||||
toast.success(
|
||||
trans(CHILL_TICKET_TICKET_ADD_COMMENT_SUCCESS),
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "set_motive":
|
||||
if (!motive.value.id) {
|
||||
toast.error(trans(CHILL_TICKET_TICKET_SET_MOTIVE_ERROR));
|
||||
} else {
|
||||
await store.dispatch("createMotive", {
|
||||
ticketId: ticket.value.id,
|
||||
motive: motive.value,
|
||||
});
|
||||
activeTab.value = "";
|
||||
toast.success(
|
||||
trans(CHILL_TICKET_TICKET_SET_MOTIVE_SUCCESS),
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "add_addressee":
|
||||
if (!addressees.value.length) {
|
||||
toast.error(trans(CHILL_TICKET_TICKET_ADD_ADDRESSEE_ERROR));
|
||||
} else {
|
||||
await store.dispatch("setAdressees", {
|
||||
ticketId: ticket.value.id,
|
||||
addressees: addressees.value,
|
||||
});
|
||||
activeTab.value = "";
|
||||
toast.success(
|
||||
trans(CHILL_TICKET_TICKET_ADD_ADDRESSEE_SUCCESS),
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error(error as string);
|
||||
}
|
||||
}
|
||||
|
||||
function handleClick() {
|
||||
alert("Sera disponible plus tard");
|
||||
}
|
||||
|
||||
function closeAllActions() {
|
||||
activeTab.value = "";
|
||||
}
|
||||
|
||||
const actionIcons = ref(store.getters.getActionIcons);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@@ -6,35 +6,21 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, watch } from "vue";
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from "vue";
|
||||
import CommentEditor from "ChillMainAssets/vuejs/_components/CommentEditor/CommentEditor.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "AddCommentComponent",
|
||||
props: {
|
||||
modelValue: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
CommentEditor,
|
||||
},
|
||||
emits: ["update:modelValue"],
|
||||
const props = defineProps<{
|
||||
modelValue?: string;
|
||||
}>();
|
||||
|
||||
setup(props, ctx) {
|
||||
const content = ref(props.modelValue);
|
||||
const emit =
|
||||
defineEmits<(e: "update:modelValue", value: string | undefined) => void>();
|
||||
|
||||
watch(content, (content) => {
|
||||
ctx.emit("update:modelValue", content);
|
||||
});
|
||||
const content = ref(props.modelValue);
|
||||
|
||||
return {
|
||||
content,
|
||||
};
|
||||
},
|
||||
watch(content, (value) => {
|
||||
emit("update:modelValue", value);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@@ -30,8 +30,11 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, computed, defineComponent, ref } from "vue";
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
|
||||
// Components
|
||||
import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge.vue";
|
||||
|
||||
// Types
|
||||
import {
|
||||
@@ -39,43 +42,32 @@ import {
|
||||
UserGroup,
|
||||
UserGroupOrUser,
|
||||
} from "../../../../../../../ChillMainBundle/Resources/public/types";
|
||||
import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "AddresseeComponent",
|
||||
components: { UserRenderBoxBadge },
|
||||
props: {
|
||||
addressees: {
|
||||
type: Array as PropType<UserGroupOrUser[]>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const userGroups = computed(
|
||||
() =>
|
||||
props.addressees.filter(
|
||||
(addressee) =>
|
||||
addressee.type == "user_group" &&
|
||||
addressee.excludeKey == "",
|
||||
) as UserGroup[],
|
||||
);
|
||||
const userGroupLevels = computed(
|
||||
() =>
|
||||
props.addressees.filter(
|
||||
(addressee) =>
|
||||
addressee.type == "user_group" &&
|
||||
addressee.excludeKey == "level",
|
||||
) as UserGroup[],
|
||||
);
|
||||
const users = computed(
|
||||
() =>
|
||||
props.addressees.filter(
|
||||
(addressee) => addressee.type == "user",
|
||||
) as User[],
|
||||
);
|
||||
return { userGroups, users, userGroupLevels };
|
||||
},
|
||||
});
|
||||
const props = defineProps<{ addressees: UserGroupOrUser[] }>();
|
||||
|
||||
const userGroups = computed(
|
||||
() =>
|
||||
props.addressees.filter(
|
||||
(addressee: UserGroupOrUser) =>
|
||||
addressee.type == "user_group" && addressee.excludeKey == "",
|
||||
) as UserGroup[],
|
||||
);
|
||||
|
||||
const userGroupLevels = computed(
|
||||
() =>
|
||||
props.addressees.filter(
|
||||
(addressee: UserGroupOrUser) =>
|
||||
addressee.type == "user_group" &&
|
||||
addressee.excludeKey == "level",
|
||||
) as UserGroup[],
|
||||
);
|
||||
|
||||
const users = computed(
|
||||
() =>
|
||||
props.addressees.filter(
|
||||
(addressee: UserGroupOrUser) => addressee.type == "user",
|
||||
) as User[],
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
@@ -66,9 +66,14 @@
|
||||
<add-persons
|
||||
:options="addPersonsOptions"
|
||||
key="add-person-ticket"
|
||||
buttonTitle="add_addressee.user_label"
|
||||
modalTitle="add_addressee.user_label"
|
||||
ref="addPersons"
|
||||
:buttonTitle="
|
||||
trans(CHILL_TICKET_TICKET_ADD_ADDRESSEE_USER_LABEL)
|
||||
"
|
||||
:modalTitle="
|
||||
trans(CHILL_TICKET_TICKET_ADD_ADDRESSEE_USER_LABEL)
|
||||
"
|
||||
:selected="selectedValues"
|
||||
:suggested="suggestedValues"
|
||||
@addNewPersons="addNewEntity"
|
||||
/>
|
||||
<div class="p-2">
|
||||
@@ -84,145 +89,120 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, computed, defineComponent, ref, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
// Types
|
||||
import { User, UserGroup, UserGroupOrUser } from "ChillMainAssets/types";
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, defineProps, defineEmits } from "vue";
|
||||
|
||||
// Components
|
||||
import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "AddresseeSelectorComponent",
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Array as PropType<UserGroupOrUser[]>,
|
||||
default: [],
|
||||
required: false,
|
||||
},
|
||||
userGroups: {
|
||||
type: Array as PropType<UserGroup[]>,
|
||||
required: true,
|
||||
},
|
||||
users: {
|
||||
type: Array as PropType<User[]>,
|
||||
required: true,
|
||||
},
|
||||
// Types
|
||||
import type { User, UserGroup, UserGroupOrUser } from "ChillMainAssets/types";
|
||||
import { SearchOptions, Suggestion } from "ChillPersonAssets/types";
|
||||
import type { addNewPersons } from "../../../types";
|
||||
|
||||
// Translations
|
||||
import {
|
||||
CHILL_TICKET_TICKET_ADD_ADDRESSEE_USER_LABEL,
|
||||
trans,
|
||||
} from "translator";
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue?: UserGroupOrUser[];
|
||||
userGroups: UserGroup[];
|
||||
users: User[];
|
||||
}>();
|
||||
|
||||
const selectedValues = ref<Suggestion[]>([]);
|
||||
const suggestedValues = ref<Suggestion[]>([]);
|
||||
|
||||
const emit =
|
||||
defineEmits<(e: "update:modelValue", value: UserGroupOrUser[]) => void>();
|
||||
|
||||
const addressees = ref<UserGroupOrUser[]>([...(props.modelValue ?? [])]);
|
||||
|
||||
const userGroupsInit = [
|
||||
...(props.modelValue ?? []).filter(
|
||||
(addressee: UserGroupOrUser) => addressee.type == "user_group",
|
||||
),
|
||||
] as UserGroup[];
|
||||
|
||||
const userGroupLevel = ref<UserGroup | Record<string, never>>(
|
||||
(userGroupsInit.filter(
|
||||
(userGroup: UserGroup) => userGroup.excludeKey == "level",
|
||||
)[0] as UserGroup) ?? {},
|
||||
);
|
||||
|
||||
const userGroup = ref<UserGroup[]>(
|
||||
userGroupsInit.filter(
|
||||
(userGroup: UserGroup) => userGroup.excludeKey == "",
|
||||
) as UserGroup[],
|
||||
);
|
||||
|
||||
const users = ref<User[]>([
|
||||
...(props.modelValue ?? []).filter(
|
||||
(addressee: UserGroupOrUser) => addressee.type == "user",
|
||||
),
|
||||
] as User[]);
|
||||
|
||||
const addPersonsOptions = {
|
||||
uniq: false,
|
||||
type: ["user"],
|
||||
priority: null,
|
||||
button: {
|
||||
size: "btn-sm",
|
||||
class: "btn-submit",
|
||||
},
|
||||
components: {
|
||||
AddPersons,
|
||||
},
|
||||
emits: ["update:modelValue"],
|
||||
} as SearchOptions;
|
||||
|
||||
setup(props, ctx) {
|
||||
const addressees = ref([...props.modelValue] as UserGroupOrUser[]);
|
||||
const userGroups = [
|
||||
...props.modelValue.filter(
|
||||
(addressee) => addressee.type == "user_group",
|
||||
),
|
||||
] as UserGroup[];
|
||||
function getUserGroupBtnColor(userGroup: UserGroup) {
|
||||
return [
|
||||
`color: ${userGroup.foregroundColor};
|
||||
.btn-check:checked + .btn-${userGroup.id} {
|
||||
color: ${userGroup.foregroundColor};
|
||||
background-color: ${userGroup.backgroundColor};
|
||||
}`,
|
||||
];
|
||||
}
|
||||
|
||||
const userGroupLevel = ref(
|
||||
userGroups.filter(
|
||||
(userGroup) => userGroup.excludeKey == "level",
|
||||
)[0] as UserGroup | {},
|
||||
);
|
||||
const userGroup = ref(
|
||||
userGroups.filter(
|
||||
(userGroup) => userGroup.excludeKey == "",
|
||||
) as UserGroup[],
|
||||
);
|
||||
const users = ref([
|
||||
...props.modelValue.filter((addressee) => addressee.type == "user"),
|
||||
] as User[]);
|
||||
const addPersons = ref();
|
||||
function addNewEntity(datas: addNewPersons) {
|
||||
const { selected } = datas;
|
||||
users.value = selected.map((selected) => selected.result);
|
||||
addressees.value = addressees.value.filter(
|
||||
(addressee) => addressee.type === "user_group",
|
||||
);
|
||||
addressees.value = [...addressees.value, ...users.value];
|
||||
emit("update:modelValue", addressees.value);
|
||||
selectedValues.value = [];
|
||||
suggestedValues.value = [];
|
||||
}
|
||||
|
||||
const { t } = useI18n();
|
||||
function removeUser(user: User) {
|
||||
users.value.splice(users.value.indexOf(user), 1);
|
||||
addressees.value = addressees.value.filter(
|
||||
(addressee) => addressee.id !== user.id,
|
||||
);
|
||||
emit("update:modelValue", addressees.value);
|
||||
}
|
||||
|
||||
function getUserGroupBtnColor(userGroup: UserGroup) {
|
||||
return [
|
||||
`color: ${userGroup.foregroundColor};
|
||||
.btn-check:checked + .btn-${userGroup.id} {
|
||||
color: ${userGroup.foregroundColor};
|
||||
background-color: ${userGroup.backgroundColor};
|
||||
}`,
|
||||
];
|
||||
}
|
||||
function addNewEntity(datas: any) {
|
||||
const { selected, modal } = datas;
|
||||
users.value = selected.map((selected: any) => selected.result);
|
||||
addressees.value = addressees.value.filter(
|
||||
(addressee) => addressee.type === "user_group",
|
||||
);
|
||||
addressees.value = [...addressees.value, ...users.value];
|
||||
ctx.emit("update:modelValue", addressees.value);
|
||||
addPersons.value.resetSearch();
|
||||
modal.showModal = false;
|
||||
}
|
||||
watch(userGroupLevel, (userGroupLevelAdd, userGroupLevelRem) => {
|
||||
const index = addressees.value.indexOf(userGroupLevelRem as UserGroup);
|
||||
if (index !== -1) {
|
||||
addressees.value.splice(index, 1);
|
||||
}
|
||||
addressees.value.push(userGroupLevelAdd as UserGroup);
|
||||
emit("update:modelValue", addressees.value);
|
||||
});
|
||||
|
||||
const addPersonsOptions = computed(() => {
|
||||
return {
|
||||
uniq: false,
|
||||
type: ["user"],
|
||||
priority: null,
|
||||
button: {
|
||||
size: "btn-sm",
|
||||
class: "btn-submit",
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
function removeUser(user: User) {
|
||||
users.value.splice(users.value.indexOf(user), 1);
|
||||
addressees.value = addressees.value.filter(
|
||||
(addressee) => addressee.id !== user.id,
|
||||
);
|
||||
ctx.emit("update:modelValue", addressees.value);
|
||||
}
|
||||
|
||||
watch(userGroupLevel, (userGroupLevelAdd, userGroupLevelRem) => {
|
||||
const index = addressees.value.indexOf(
|
||||
userGroupLevelRem as UserGroup,
|
||||
);
|
||||
if (index !== -1) {
|
||||
addressees.value.splice(index, 1);
|
||||
}
|
||||
addressees.value.push(userGroupLevelAdd as UserGroup);
|
||||
ctx.emit("update:modelValue", addressees.value);
|
||||
});
|
||||
|
||||
watch(userGroup, (userGroupAdd) => {
|
||||
const userGroupLevel = addressees.value.filter(
|
||||
(addressee) =>
|
||||
addressee.type == "user_group" &&
|
||||
addressee.excludeKey == "level",
|
||||
) as UserGroup[];
|
||||
const users = addressees.value.filter(
|
||||
(addressee) => addressee.type == "user",
|
||||
) as User[];
|
||||
addressees.value = [...users, ...userGroupLevel, ...userGroupAdd];
|
||||
ctx.emit("update:modelValue", addressees.value);
|
||||
});
|
||||
|
||||
return {
|
||||
addressees,
|
||||
userGroupLevel,
|
||||
userGroup,
|
||||
users,
|
||||
addPersons,
|
||||
addPersonsOptions,
|
||||
addNewEntity,
|
||||
removeUser,
|
||||
getUserGroupBtnColor,
|
||||
customUserGroupLabel(selectedUserGroup: UserGroup) {
|
||||
return selectedUserGroup.label
|
||||
? selectedUserGroup.label.fr
|
||||
: t("add_addresseeuser_group_label");
|
||||
},
|
||||
};
|
||||
},
|
||||
watch(userGroup, (userGroupAdd) => {
|
||||
const userGroupLevelArr = addressees.value.filter(
|
||||
(addressee) =>
|
||||
addressee.type == "user_group" && addressee.excludeKey == "level",
|
||||
) as UserGroup[];
|
||||
const usersArr = addressees.value.filter(
|
||||
(addressee) => addressee.type == "user",
|
||||
) as User[];
|
||||
addressees.value = [...usersArr, ...userGroupLevelArr, ...userGroupAdd];
|
||||
emit("update:modelValue", addressees.value);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
{{ ticket.currentMotive.label.fr }}
|
||||
</h1>
|
||||
<p class="chill-no-data-statement" v-else>
|
||||
{{ $t("banner.no_motive") }}
|
||||
{{ trans(CHILL_TICKET_TICKET_BANNER_NO_MOTIVE) }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -18,13 +18,13 @@
|
||||
class="badge text-bg-chill-green text-white"
|
||||
style="font-size: 1rem"
|
||||
>
|
||||
{{ $t("banner.open") }}
|
||||
{{ trans(CHILL_TICKET_TICKET_BANNER_OPEN) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-end">
|
||||
<p class="created-at-timespan" v-if="ticket.createdAt">
|
||||
{{
|
||||
$t("banner.since", {
|
||||
trans(CHILL_TICKET_TICKET_BANNER_SINCE, {
|
||||
time: since,
|
||||
})
|
||||
}}
|
||||
@@ -39,7 +39,7 @@
|
||||
<div class="row justify-content-between">
|
||||
<div class="col-md-6 col-sm-12 ps-md-5 ps-xxl-0">
|
||||
<h3 class="text-primary">
|
||||
{{ $t("banner.concerned_patient") }}
|
||||
{{ trans(CHILL_TICKET_TICKET_BANNER_CONCERNED_USAGER) }}
|
||||
</h3>
|
||||
<on-the-fly
|
||||
v-for="person in ticket.currentPersons"
|
||||
@@ -49,10 +49,13 @@
|
||||
:buttonText="person.textAge"
|
||||
:displayBadge="'true' === 'true'"
|
||||
action="show"
|
||||
CHILL_TICKET_TICKET_BANNER_CONCERNED_USAGER
|
||||
></on-the-fly>
|
||||
</div>
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<h3 class="text-primary">{{ $t("banner.speaker") }}</h3>
|
||||
<h3 class="text-primary">
|
||||
{{ trans(CHILL_TICKET_TICKET_BANNER_SPEAKER) }}
|
||||
</h3>
|
||||
<addressee-component
|
||||
:addressees="ticket.currentAddressees"
|
||||
/>
|
||||
@@ -69,81 +72,91 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, computed, defineComponent, ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from "vue";
|
||||
|
||||
// Components
|
||||
import PersonRenderBox from "../../../../../../../ChillPersonBundle/Resources/public/vuejs/_components/Entity/PersonRenderBox.vue";
|
||||
import AddresseeComponent from "./AddresseeComponent.vue";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
||||
|
||||
// Types
|
||||
import { Ticket } from "../../../types";
|
||||
import { ISOToDatetime } from "../../../../../../../ChillMainBundle/Resources/public/chill/js/date";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "BannerComponent",
|
||||
props: {
|
||||
ticket: {
|
||||
type: Object as PropType<Ticket>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
OnTheFly,
|
||||
PersonRenderBox,
|
||||
AddresseeComponent,
|
||||
},
|
||||
setup(props) {
|
||||
const { t } = useI18n();
|
||||
const today = ref(new Date());
|
||||
const createdAt = ref(props.ticket.createdAt);
|
||||
// Translations
|
||||
import {
|
||||
trans,
|
||||
CHILL_TICKET_TICKET_BANNER_NO_MOTIVE,
|
||||
CHILL_TICKET_TICKET_BANNER_OPEN,
|
||||
CHILL_TICKET_TICKET_BANNER_SINCE,
|
||||
CHILL_TICKET_TICKET_BANNER_CONCERNED_USAGER,
|
||||
CHILL_TICKET_TICKET_BANNER_SPEAKER,
|
||||
CHILL_TICKET_TICKET_BANNER_DAYS,
|
||||
CHILL_TICKET_TICKET_BANNER_HOURS,
|
||||
CHILL_TICKET_TICKET_BANNER_MINUTES,
|
||||
CHILL_TICKET_TICKET_BANNER_SECONDS,
|
||||
CHILL_TICKET_TICKET_BANNER_AND,
|
||||
} from "translator";
|
||||
|
||||
setInterval(function () {
|
||||
today.value = new Date();
|
||||
}, 5000);
|
||||
const props = defineProps<{
|
||||
ticket: Ticket;
|
||||
}>();
|
||||
|
||||
const since = computed(() => {
|
||||
if (null === createdAt.value) {
|
||||
return "";
|
||||
}
|
||||
const date = ISOToDatetime(createdAt.value.datetime);
|
||||
const today = ref(new Date());
|
||||
const createdAt = ref(props.ticket.createdAt);
|
||||
|
||||
if (null === date) {
|
||||
return "";
|
||||
}
|
||||
setInterval(() => {
|
||||
today.value = new Date();
|
||||
}, 5000);
|
||||
|
||||
const timeDiff = Math.abs(today.value.getTime() - date.getTime());
|
||||
const daysDiff = Math.floor(timeDiff / (1000 * 3600 * 24));
|
||||
const hoursDiff = Math.floor(
|
||||
(timeDiff % (1000 * 3600 * 24)) / (1000 * 3600),
|
||||
);
|
||||
const minutesDiff = Math.floor(
|
||||
(timeDiff % (1000 * 3600)) / (1000 * 60),
|
||||
);
|
||||
const secondsDiff = Math.floor((timeDiff % (1000 * 60)) / 1000);
|
||||
const since = computed(() => {
|
||||
if (createdAt.value == null) {
|
||||
return "";
|
||||
}
|
||||
const date = ISOToDatetime(createdAt.value.datetime);
|
||||
|
||||
if (daysDiff < 1 && hoursDiff < 1 && minutesDiff < 1) {
|
||||
return `${t("banner.seconds", { count: secondsDiff })}`;
|
||||
} else if (daysDiff < 1 && hoursDiff < 1) {
|
||||
return `${t("banner.minutes", { count: minutesDiff })}`;
|
||||
} else if (daysDiff < 1) {
|
||||
return `${t("banner.hours", { count: hoursDiff })}
|
||||
${t("banner.minutes", { count: minutesDiff })}`;
|
||||
} else {
|
||||
return `${t("banner.days", { count: daysDiff })}, ${t(
|
||||
"banner.hours",
|
||||
{
|
||||
count: hoursDiff,
|
||||
},
|
||||
)} ${t("banner.minutes", {
|
||||
count: minutesDiff,
|
||||
})}`;
|
||||
}
|
||||
if (date == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const timeDiff = Math.abs(today.value.getTime() - date.getTime());
|
||||
const daysDiff = Math.floor(timeDiff / (1000 * 3600 * 24));
|
||||
const hoursDiff = Math.floor(
|
||||
(timeDiff % (1000 * 3600 * 24)) / (1000 * 3600),
|
||||
);
|
||||
const minutesDiff = Math.floor((timeDiff % (1000 * 3600)) / (1000 * 60));
|
||||
const secondsDiff = Math.floor((timeDiff % (1000 * 60)) / 1000);
|
||||
|
||||
// On construit la liste des parties à afficher
|
||||
const parts: string[] = [];
|
||||
if (daysDiff > 0) {
|
||||
parts.push(trans(CHILL_TICKET_TICKET_BANNER_DAYS, { count: daysDiff }));
|
||||
}
|
||||
if (hoursDiff > 0 || daysDiff > 0) {
|
||||
parts.push(
|
||||
trans(CHILL_TICKET_TICKET_BANNER_HOURS, { count: hoursDiff }),
|
||||
);
|
||||
}
|
||||
if (minutesDiff > 0 || hoursDiff > 0 || daysDiff > 0) {
|
||||
parts.push(
|
||||
trans(CHILL_TICKET_TICKET_BANNER_MINUTES, { count: minutesDiff }),
|
||||
);
|
||||
}
|
||||
if (parts.length === 0) {
|
||||
return trans(CHILL_TICKET_TICKET_BANNER_SECONDS, {
|
||||
count: secondsDiff,
|
||||
});
|
||||
|
||||
return { since };
|
||||
},
|
||||
}
|
||||
if (parts.length > 1) {
|
||||
const last = parts.pop();
|
||||
return (
|
||||
parts.join(", ") +
|
||||
" " +
|
||||
trans(CHILL_TICKET_TICKET_BANNER_AND) +
|
||||
" " +
|
||||
last
|
||||
);
|
||||
}
|
||||
return parts[0];
|
||||
});
|
||||
</script>
|
||||
|
@@ -10,10 +10,10 @@
|
||||
open-direction="top"
|
||||
:multiple="false"
|
||||
:searchable="true"
|
||||
:placeholder="$t('set_motive.label')"
|
||||
:select-label="$t('multiselect.select_label')"
|
||||
:deselect-label="$t('multiselect.deselect_label')"
|
||||
:selected-label="$t('multiselect.selected_label')"
|
||||
:placeholder="trans(CHILL_TICKET_TICKET_SET_MOTIVE_LABEL)"
|
||||
:select-label="trans(MULTISELECT_SELECT_LABEL)"
|
||||
:deselect-label="trans(MULTISELECT_DESELECT_LABEL)"
|
||||
:selected-label="trans(MULTISELECT_SELECTED_LABEL)"
|
||||
:options="motives"
|
||||
v-model="motive"
|
||||
class="mb-4"
|
||||
@@ -22,47 +22,46 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent, ref, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from "vue";
|
||||
import VueMultiselect from "vue-multiselect";
|
||||
|
||||
// Types
|
||||
import { Motive } from "../../../types";
|
||||
|
||||
export default defineComponent({
|
||||
name: "MotiveSelectorComponent",
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Object as PropType<Motive>,
|
||||
required: false,
|
||||
},
|
||||
motives: {
|
||||
type: Object as PropType<Motive[]>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
VueMultiselect,
|
||||
},
|
||||
emits: ["update:modelValue"],
|
||||
// Translations
|
||||
import {
|
||||
trans,
|
||||
CHILL_TICKET_TICKET_SET_MOTIVE_LABEL,
|
||||
MULTISELECT_SELECT_LABEL,
|
||||
MULTISELECT_DESELECT_LABEL,
|
||||
MULTISELECT_SELECTED_LABEL,
|
||||
} from "translator";
|
||||
|
||||
setup(props, ctx) {
|
||||
const motive = ref(props.modelValue);
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
modelValue?: Motive;
|
||||
motives: Motive[];
|
||||
}>();
|
||||
|
||||
watch(motive, (motive) => {
|
||||
ctx.emit("update:modelValue", motive);
|
||||
});
|
||||
const emit =
|
||||
defineEmits<(e: "update:modelValue", value: Motive | undefined) => void>();
|
||||
|
||||
return {
|
||||
motive,
|
||||
customLabel(motive: Motive) {
|
||||
return motive.label ? motive.label.fr : t("set_motive.label");
|
||||
},
|
||||
};
|
||||
},
|
||||
const motive = ref(props.modelValue);
|
||||
|
||||
watch(motive, (val) => {
|
||||
emit("update:modelValue", val);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
motive.value = val;
|
||||
},
|
||||
);
|
||||
|
||||
function customLabel(motive: Motive) {
|
||||
return motive?.label?.fr ?? trans(CHILL_TICKET_TICKET_SET_MOTIVE_LABEL);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@@ -1,12 +1,68 @@
|
||||
<template>
|
||||
<div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center">
|
||||
<add-persons
|
||||
:options="addPersonsOptions"
|
||||
key="add-person-selector"
|
||||
:buttonTitle="trans(CHILL_TICKET_TICKET_SET_PERSONS_USER_LABEL)"
|
||||
:modalTitle="trans(CHILL_TICKET_TICKET_SET_PERSONS_USER_LABEL)"
|
||||
:selected="selectedValues"
|
||||
:suggested="suggestedValues"
|
||||
@addNewPersons="addNewEntity"
|
||||
/>
|
||||
<div class="p-2">
|
||||
<ul class="list-suggest inline remove-items">
|
||||
<li v-for="person in currentPersons" :key="person.id">
|
||||
<span
|
||||
:title="`${person.firstName} ${person.lastName}`"
|
||||
@click="removePerson(person)"
|
||||
>
|
||||
{{ `${person.firstName} ${person.lastName}` }}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="record_actions">
|
||||
<li class="cancel">
|
||||
<button
|
||||
class="btn btn-cancel"
|
||||
type="button"
|
||||
@click="emit('closeRequested')"
|
||||
>
|
||||
{{ trans(CHILL_TICKET_TICKET_ACTIONS_TOOLBAR_CANCEL) }}
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button class="btn btn-save" type="submit" @click.prevent="save">
|
||||
{{ trans(CHILL_TICKET_TICKET_ACTIONS_TOOLBAR_SAVE) }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, inject, reactive, ref } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue";
|
||||
import { computed, inject, reactive } from "vue";
|
||||
import { Ticket } from "../../../types";
|
||||
import { Person } from "../../../../../../../ChillPersonBundle/Resources/public/types";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
||||
import { ToastPluginApi } from "vue-toast-notification";
|
||||
|
||||
// Components
|
||||
import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue";
|
||||
|
||||
// Types
|
||||
import { SearchOptions, Suggestion, Person } from "ChillPersonAssets/types";
|
||||
import { Ticket } from "../../../types";
|
||||
|
||||
// Translations
|
||||
import {
|
||||
trans,
|
||||
CHILL_TICKET_TICKET_SET_PERSONS_USER_LABEL,
|
||||
CHILL_TICKET_TICKET_ACTIONS_TOOLBAR_CANCEL,
|
||||
CHILL_TICKET_TICKET_ACTIONS_TOOLBAR_SAVE,
|
||||
CHILL_TICKET_TICKET_SET_PERSONS_SUCCESS,
|
||||
} from "translator";
|
||||
|
||||
const emit = defineEmits<(e: "closeRequested") => void>();
|
||||
|
||||
const store = useStore();
|
||||
@@ -19,9 +75,13 @@ const addPersonsOptions = {
|
||||
type: ["person"],
|
||||
priority: null,
|
||||
button: {
|
||||
size: "btn-sm",
|
||||
class: "btn-submit",
|
||||
},
|
||||
};
|
||||
} as SearchOptions;
|
||||
|
||||
const selectedValues = ref<Suggestion[]>([]);
|
||||
const suggestedValues = ref<Suggestion[]>([]);
|
||||
|
||||
const added: Person[] = reactive([]);
|
||||
const removed: Person[] = reactive([]);
|
||||
@@ -50,14 +110,12 @@ const removePerson = (p: Person) => {
|
||||
removed.push(p);
|
||||
};
|
||||
|
||||
const addNewEntity = (n: {
|
||||
modal: { showModal: boolean };
|
||||
selected: { result: Person }[];
|
||||
}) => {
|
||||
n.modal.showModal = false;
|
||||
const addNewEntity = (n: { selected: { result: Person }[] }) => {
|
||||
for (let p of n.selected) {
|
||||
added.push(p.result);
|
||||
}
|
||||
selectedValues.value = [];
|
||||
suggestedValues.value = [];
|
||||
};
|
||||
|
||||
const save = async function (): Promise<void> {
|
||||
@@ -65,64 +123,14 @@ const save = async function (): Promise<void> {
|
||||
await store.dispatch("setPersons", {
|
||||
persons: computeCurrentPersons(persons.value, added, removed),
|
||||
});
|
||||
toast.success("Patients concernés sauvegardés");
|
||||
} catch (e: any) {
|
||||
console.error("error while saving", e);
|
||||
toast.error((e as Error).message);
|
||||
toast.success(trans(CHILL_TICKET_TICKET_SET_PERSONS_SUCCESS));
|
||||
} catch (error) {
|
||||
toast.error((error as Error).message);
|
||||
return Promise.resolve();
|
||||
}
|
||||
emit("closeRequested");
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<ul v-if="currentPersons.length > 0" class="person-list">
|
||||
<li v-for="person in currentPersons" :key="person.id">
|
||||
<on-the-fly
|
||||
:type="person.type"
|
||||
:id="person.id"
|
||||
:buttonText="person.textAge"
|
||||
:displayBadge="'true' === 'true'"
|
||||
action="show"
|
||||
></on-the-fly>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-delete remove-person"
|
||||
@click="removePerson(person)"
|
||||
></button>
|
||||
</li>
|
||||
</ul>
|
||||
<p v-else class="chill-no-data-statement">Aucun patient</p>
|
||||
</div>
|
||||
<ul class="record_actions">
|
||||
<li class="cancel">
|
||||
<button
|
||||
class="btn btn-cancel"
|
||||
type="button"
|
||||
@click="emit('closeRequested')"
|
||||
>
|
||||
{{ $t("ticket.cancel") }}
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<add-persons
|
||||
:options="addPersonsOptions"
|
||||
key="add-person-ticket"
|
||||
buttonTitle="set_persons.user_label"
|
||||
modalTitle="set_persons.user_label"
|
||||
ref="addPersons"
|
||||
@addNewPersons="addNewEntity"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<button class="btn btn-save" type="submit" @click.prevent="save">
|
||||
{{ $t("ticket.save") }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
ul.person-list {
|
||||
list-style-type: none;
|
||||
|
@@ -3,31 +3,16 @@
|
||||
<addressee-component :addressees="addressees" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent } from "vue";
|
||||
|
||||
<script setup lang="ts">
|
||||
// Types
|
||||
import { UserGroupOrUser } from "../../../../../../../ChillMainBundle/Resources/public/types";
|
||||
|
||||
// Components
|
||||
import AddresseeComponent from "./AddresseeComponent.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "TicketHistoryAddresseeComponenvt",
|
||||
props: {
|
||||
addressees: {
|
||||
type: Array as PropType<UserGroupOrUser[]>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
AddresseeComponent,
|
||||
},
|
||||
setup() {
|
||||
return {};
|
||||
},
|
||||
});
|
||||
defineProps<{
|
||||
addressees: UserGroupOrUser[];
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
@@ -6,55 +6,41 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent } from "vue";
|
||||
<script setup lang="ts">
|
||||
import { marked } from "marked";
|
||||
import DOMPurify from "dompurify";
|
||||
|
||||
// Types
|
||||
import { Comment } from "../../../types";
|
||||
|
||||
export default defineComponent({
|
||||
name: "TicketHistoryCommentComponent",
|
||||
props: {
|
||||
commentHistory: {
|
||||
type: Object as PropType<Comment>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const preprocess = (markdown: string): string => {
|
||||
return markdown;
|
||||
};
|
||||
defineProps<{ commentHistory: Comment }>();
|
||||
|
||||
const postprocess = (html: string): string => {
|
||||
DOMPurify.addHook("afterSanitizeAttributes", (node: any) => {
|
||||
if ("target" in node) {
|
||||
node.setAttribute("target", "_blank");
|
||||
node.setAttribute("rel", "noopener noreferrer");
|
||||
}
|
||||
if (
|
||||
!node.hasAttribute("target") &&
|
||||
(node.hasAttribute("xlink:href") ||
|
||||
node.hasAttribute("href"))
|
||||
) {
|
||||
node.setAttribute("xlink:show", "new");
|
||||
}
|
||||
});
|
||||
const preprocess = (markdown: string): string => {
|
||||
return markdown;
|
||||
};
|
||||
|
||||
return DOMPurify.sanitize(html);
|
||||
};
|
||||
const postprocess = (html: string): string => {
|
||||
DOMPurify.addHook("afterSanitizeAttributes", (node: Element) => {
|
||||
if ("target" in node) {
|
||||
node.setAttribute("target", "_blank");
|
||||
node.setAttribute("rel", "noopener noreferrer");
|
||||
}
|
||||
if (
|
||||
!node.hasAttribute("target") &&
|
||||
(node.hasAttribute("xlink:href") || node.hasAttribute("href"))
|
||||
) {
|
||||
node.setAttribute("xlink:show", "new");
|
||||
}
|
||||
});
|
||||
|
||||
const convertMarkdownToHtml = (markdown: string): string => {
|
||||
marked.use({ hooks: { postprocess, preprocess } });
|
||||
const rawHtml = marked(markdown) as string;
|
||||
return rawHtml;
|
||||
};
|
||||
return {
|
||||
convertMarkdownToHtml,
|
||||
};
|
||||
},
|
||||
});
|
||||
return DOMPurify.sanitize(html);
|
||||
};
|
||||
|
||||
const convertMarkdownToHtml = (markdown: string): string => {
|
||||
marked.use({ hooks: { postprocess, preprocess } });
|
||||
const rawHtml = marked(markdown) as string;
|
||||
return rawHtml;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
@@ -1,4 +1,9 @@
|
||||
<template>
|
||||
<p>Ticket créé par {{ props.by.text }}</p>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// Types
|
||||
import { User } from "../../../../../../../ChillMainBundle/Resources/public/types";
|
||||
|
||||
interface TicketHistoryCreateComponentConfig {
|
||||
@@ -8,8 +13,4 @@ interface TicketHistoryCreateComponentConfig {
|
||||
const props = defineProps<TicketHistoryCreateComponentConfig>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<p>Ticket créé par {{ props.by.text }}</p>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
@@ -50,9 +50,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent, ref, computed } from "vue";
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
|
||||
// Types
|
||||
@@ -66,72 +65,41 @@ import TicketHistoryCommentComponent from "./TicketHistoryCommentComponent.vue";
|
||||
import TicketHistoryAddresseeComponent from "./TicketHistoryAddresseeComponent.vue";
|
||||
import TicketHistoryCreateComponent from "./TicketHistoryCreateComponent.vue";
|
||||
import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge.vue";
|
||||
|
||||
// Utils
|
||||
import { ISOToDatetime } from "../../../../../../../ChillMainBundle/Resources/public/chill/js/date";
|
||||
|
||||
export default defineComponent({
|
||||
name: "TicketHistoryListComponent",
|
||||
components: {
|
||||
UserRenderBoxBadge,
|
||||
TicketHistoryPersonComponent,
|
||||
TicketHistoryMotiveComponent,
|
||||
TicketHistoryCommentComponent,
|
||||
TicketHistoryAddresseeComponent,
|
||||
TicketHistoryCreateComponent,
|
||||
},
|
||||
props: {
|
||||
history: {
|
||||
type: Array as PropType<TicketHistoryLine[]>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
defineProps<{ history: TicketHistoryLine[] }>();
|
||||
|
||||
setup() {
|
||||
const store = useStore();
|
||||
const store = useStore();
|
||||
|
||||
const explainSentence = (history: TicketHistoryLine): string => {
|
||||
switch (history.event_type) {
|
||||
case "add_comment":
|
||||
return "Nouveau commentaire";
|
||||
case "addressees_state":
|
||||
return "Attributions";
|
||||
case "persons_state":
|
||||
return "Patients concernés";
|
||||
case "set_motive":
|
||||
return "Nouveau motifs";
|
||||
case "create_ticket":
|
||||
return "Ticket créé";
|
||||
}
|
||||
};
|
||||
const actionIcons = ref(store.getters.getActionIcons);
|
||||
|
||||
function formatDate(d: DateTime): string {
|
||||
const date = ISOToDatetime(d.datetime);
|
||||
|
||||
if (date === null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const month = date.toLocaleString("default", { month: "long" });
|
||||
return `${date.getDate()} ${month} ${date.getFullYear()}, ${date.toLocaleTimeString()}`;
|
||||
}
|
||||
|
||||
return {
|
||||
actionIcons: ref(store.getters.getActionIcons),
|
||||
formatDate,
|
||||
explainSentence,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
div.history-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
|
||||
& > div.description {
|
||||
margin-right: auto;
|
||||
function explainSentence(history: TicketHistoryLine): string {
|
||||
switch (history.event_type) {
|
||||
case "add_comment":
|
||||
return "Nouveau commentaire";
|
||||
case "addressees_state":
|
||||
return "Attributions";
|
||||
case "persons_state":
|
||||
return "Usagés concernés";
|
||||
case "set_motive":
|
||||
return "Nouveau motifs";
|
||||
case "create_ticket":
|
||||
return "Ticket créé";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
function formatDate(d: DateTime): string {
|
||||
const date = ISOToDatetime(d.datetime);
|
||||
|
||||
if (date === null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const month = date.toLocaleString("default", { month: "long" });
|
||||
return `${date.getDate()} ${month} ${date.getFullYear()}, ${date.toLocaleTimeString()}`;
|
||||
}
|
||||
</script>
|
||||
|
@@ -4,23 +4,11 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent } from "vue";
|
||||
|
||||
<script lang="ts" setup>
|
||||
// Types
|
||||
import { MotiveHistory } from "../../../types";
|
||||
|
||||
export default defineComponent({
|
||||
name: "TicketHistoryMotiveComponent",
|
||||
props: {
|
||||
motiveHistory: {
|
||||
type: Object as PropType<MotiveHistory>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
setup() {},
|
||||
});
|
||||
defineProps<{ motiveHistory: MotiveHistory }>();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
@@ -6,7 +6,7 @@
|
||||
:type="person.type"
|
||||
:id="person.id"
|
||||
:buttonText="person.textAge"
|
||||
:displayBadge="'true' === 'true'"
|
||||
:displayBadge="true"
|
||||
action="show"
|
||||
></on-the-fly>
|
||||
</li>
|
||||
@@ -14,27 +14,13 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent } from "vue";
|
||||
|
||||
// Type
|
||||
import { PersonsState } from "../../../types";
|
||||
<script setup lang="ts">
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "TicketHistoryPersonComponent",
|
||||
props: {
|
||||
personHistory: {
|
||||
type: Object as PropType<PersonsState>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
OnTheFly,
|
||||
},
|
||||
// Types
|
||||
import { PersonsState } from "../../../types";
|
||||
|
||||
setup() {},
|
||||
});
|
||||
defineProps<{ personHistory: PersonsState }>();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
>
|
||||
{{ $t("ticket.previous_tickets") }}
|
||||
{{ trans(CHILL_TICKET_TICKET_PREVIOUS_TICKETS) }}
|
||||
<span
|
||||
class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-chill-green"
|
||||
>
|
||||
@@ -19,27 +19,18 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent } from "vue";
|
||||
<script setup lang="ts">
|
||||
// Translations
|
||||
import { trans, CHILL_TICKET_TICKET_PREVIOUS_TICKETS } from "translator";
|
||||
|
||||
// Types
|
||||
import { Ticket } from "../../../types";
|
||||
|
||||
export default defineComponent({
|
||||
name: "TicketSelectorComponent",
|
||||
props: {
|
||||
tickets: {
|
||||
type: Object as PropType<Ticket[]>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
function handleClick() {
|
||||
alert("Sera disponible plus tard");
|
||||
}
|
||||
return { handleClick };
|
||||
},
|
||||
});
|
||||
defineProps<{ tickets: Ticket[] }>();
|
||||
|
||||
function handleClick() {
|
||||
alert("Sera disponible plus tard");
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
@@ -1,56 +0,0 @@
|
||||
import { multiSelectMessages } from "../../../../../../../ChillMainBundle/Resources/public/vuejs/_js/i18n";
|
||||
import { personMessages } from "../../../../../../../ChillPersonBundle/Resources/public/vuejs/_js/i18n";
|
||||
|
||||
const messages = {
|
||||
fr: {
|
||||
ticket: {
|
||||
previous_tickets: "Précédents tickets",
|
||||
cancel: "Annuler",
|
||||
save: "Enregistrer",
|
||||
close: "Fermer",
|
||||
},
|
||||
history: {
|
||||
person: "Ouverture par appel téléphonique de ",
|
||||
user: "Prise en charge par ",
|
||||
},
|
||||
add_comment: {
|
||||
title: "Commentaire",
|
||||
label: "Ajouter un commentaire",
|
||||
success: "Commentaire enregistré",
|
||||
content: "Ajouter un commentaire",
|
||||
error: "Aucun commentaire ajouté",
|
||||
},
|
||||
set_motive: {
|
||||
title: "Motif",
|
||||
label: "Choisir un motif",
|
||||
success: "Motif enregistré",
|
||||
error: "Aucun motif sélectionné",
|
||||
},
|
||||
add_addressee: {
|
||||
title: "Attribuer",
|
||||
user_group_label: "Attributer à un groupe",
|
||||
user_label: "Attribuer à un ou plusieurs utilisateurs",
|
||||
success: "Attribution effectuée",
|
||||
error: "Aucun destinataire sélectionné",
|
||||
},
|
||||
set_persons: {
|
||||
title: "Patients concernés",
|
||||
user_label: "Ajouter un patient",
|
||||
},
|
||||
banner: {
|
||||
concerned_patient: "Patients concernés",
|
||||
speaker: "Attribué à",
|
||||
open: "Ouvert",
|
||||
since: "Depuis {time}",
|
||||
and: "et",
|
||||
days: "|1 jour|{count} jours",
|
||||
hours: "|1 heure et|{count} heures",
|
||||
minutes: "|1 minute|{count} minutes",
|
||||
seconds: "|1 seconde|{count} secondes",
|
||||
no_motive: "Pas de motif",
|
||||
},
|
||||
},
|
||||
};
|
||||
Object.assign(messages.fr, multiSelectMessages.fr);
|
||||
Object.assign(messages.fr, personMessages.fr);
|
||||
export default messages;
|
@@ -1,13 +1,10 @@
|
||||
import App from "./App.vue";
|
||||
import { createApp } from "vue";
|
||||
|
||||
import { _createI18n } from "../../../../../../ChillMainBundle/Resources/public/vuejs/_js/i18n";
|
||||
|
||||
import VueToast from "vue-toast-notification";
|
||||
import "vue-toast-notification/dist/theme-sugar.css";
|
||||
|
||||
import { store } from "./store";
|
||||
import messages from "./i18n/messages";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
@@ -15,16 +12,11 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
const i18n = _createI18n(messages, false);
|
||||
|
||||
const _app = createApp({
|
||||
template: "<app></app>",
|
||||
});
|
||||
|
||||
_app.use(store)
|
||||
.use(i18n)
|
||||
// Cant use this.$toast in components in composition API so we need to provide it
|
||||
// Fix: with vue-toast-notification@^3
|
||||
.use(VueToast)
|
||||
.provide("toast", _app.config.globalProperties.$toast)
|
||||
.component("app", App)
|
||||
|
@@ -0,0 +1,66 @@
|
||||
chill_ticket:
|
||||
list:
|
||||
title: Tickets
|
||||
filter:
|
||||
to_me: Tickets qui me sont attribués
|
||||
in_alert: Tickets en alerte (délai de résolution dépassé)
|
||||
created_between: Créés entre
|
||||
ticket:
|
||||
previous_tickets: "Précédents tickets"
|
||||
actions_toolbar:
|
||||
cancel: "Annuler"
|
||||
save: "Enregistrer"
|
||||
close: "Fermer"
|
||||
add_comment:
|
||||
title: "Commentaire"
|
||||
label: "Ajouter un commentaire"
|
||||
success: "Commentaire enregistré"
|
||||
content: "Ajouter un commentaire"
|
||||
error: "Aucun commentaire ajouté"
|
||||
set_motive:
|
||||
title: "Motif"
|
||||
label: "Choisir un motif"
|
||||
success: "Motif enregistré"
|
||||
error: "Aucun motif sélectionné"
|
||||
add_addressee:
|
||||
title: "Attribuer"
|
||||
user_group_label: "Attributer à un groupe"
|
||||
user_label: "Attribuer à un ou plusieurs utilisateurs"
|
||||
success: "Attribution effectuée"
|
||||
error: "Aucun destinataire sélectionné"
|
||||
set_persons:
|
||||
title: "Usagers concernés"
|
||||
user_label: "Ajouter un usager"
|
||||
success: "Usager ajouté"
|
||||
error: "Aucun usager sélectionné"
|
||||
banner:
|
||||
concerned_usager: "Usagers concernés"
|
||||
speaker: "Attribué à"
|
||||
open: "Ouvert"
|
||||
since: "Depuis {time}"
|
||||
and: "et"
|
||||
days: >-
|
||||
{count, plural,
|
||||
=0 {aucun jour}
|
||||
=1 {1 jour}
|
||||
other {# jours}
|
||||
}
|
||||
hours: >-
|
||||
{count, plural,
|
||||
=0 {aucune heure}
|
||||
=1 {1 heure}
|
||||
other {# heures}
|
||||
}
|
||||
minutes: >-
|
||||
{count, plural,
|
||||
=0 {aucune minute}
|
||||
=1 {1 minute}
|
||||
other {# minutes}
|
||||
}
|
||||
seconds: >-
|
||||
{count, plural,
|
||||
=0 {aucune seconde}
|
||||
=1 {1 seconde}
|
||||
other {# secondes}
|
||||
}
|
||||
no_motive: "Pas de motif"
|
@@ -1,9 +0,0 @@
|
||||
chill_ticket:
|
||||
list:
|
||||
title: Tickets
|
||||
filter:
|
||||
to_me: Tickets qui me sont attribués
|
||||
in_alert: Tickets en alerte (délai de résolution dépassé)
|
||||
created_between: Créés entre
|
||||
|
||||
|
Reference in New Issue
Block a user