mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-09-18 20:54:59 +00:00
Misc: homepage widget with tickets, and improvements in ticket list
This commit is contained in:
@@ -1,15 +0,0 @@
|
||||
import { createApp } from "vue";
|
||||
import { _createI18n } from "ChillMainAssets/vuejs/_js/i18n";
|
||||
import { appMessages } from "ChillMainAssets/vuejs/HomepageWidget/js/i18n";
|
||||
import { store } from "ChillMainAssets/vuejs/HomepageWidget/js/store";
|
||||
import App from "ChillMainAssets/vuejs/HomepageWidget/App";
|
||||
|
||||
const i18n = _createI18n(appMessages);
|
||||
|
||||
const app = createApp({
|
||||
template: `<app></app>`,
|
||||
})
|
||||
.use(store)
|
||||
.use(i18n)
|
||||
.component("app", App)
|
||||
.mount("#homepage_widget");
|
@@ -0,0 +1,6 @@
|
||||
import App from "ChillMainAssets/vuejs/HomepageWidget/App.vue";
|
||||
import { createApp } from "vue";
|
||||
import { store } from "ChillMainAssets/vuejs/HomepageWidget/store";
|
||||
|
||||
const _app = createApp(App);
|
||||
_app.use(store).mount("#homepage_widget");
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<h2>{{ $t("main_title") }}</h2>
|
||||
<h2>{{ trans(MAIN_TITLE) }}</h2>
|
||||
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="nav-item">
|
||||
@@ -11,14 +11,24 @@
|
||||
<i class="fa fa-dashboard" />
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a
|
||||
class="nav-link"
|
||||
:class="{ active: activeTab === 'MyTickets' }"
|
||||
@click="selectTab('MyTickets')"
|
||||
>
|
||||
{{ trans(MY_TICKETS_TAB) }}
|
||||
<tab-counter :count="ticketListState.value?.count || 0" />
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a
|
||||
class="nav-link"
|
||||
:class="{ active: activeTab === 'MyNotifications' }"
|
||||
@click="selectTab('MyNotifications')"
|
||||
>
|
||||
{{ $t("my_notifications.tab") }}
|
||||
<tab-counter :count="state.notifications.count" />
|
||||
{{ trans(MY_NOTIFICATIONS_TAB) }}
|
||||
<tab-counter :count="state.value?.notifications?.count || 0" />
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
@@ -27,25 +37,17 @@
|
||||
:class="{ active: activeTab === 'MyAccompanyingCourses' }"
|
||||
@click="selectTab('MyAccompanyingCourses')"
|
||||
>
|
||||
{{ $t("my_accompanying_courses.tab") }}
|
||||
{{ trans(MY_ACCOMPANYING_COURSES_TAB) }}
|
||||
</a>
|
||||
</li>
|
||||
<!-- <li class="nav-item">
|
||||
<a class="nav-link"
|
||||
:class="{'active': activeTab === 'MyWorks'}"
|
||||
@click="selectTab('MyWorks')">
|
||||
{{ $t('my_works.tab') }}
|
||||
<tab-counter :count="state.works.count"></tab-counter>
|
||||
</a>
|
||||
</li> -->
|
||||
<li class="nav-item">
|
||||
<a
|
||||
class="nav-link"
|
||||
:class="{ active: activeTab === 'MyEvaluations' }"
|
||||
@click="selectTab('MyEvaluations')"
|
||||
>
|
||||
{{ $t("my_evaluations.tab") }}
|
||||
<tab-counter :count="state.evaluations.count" />
|
||||
{{ trans(MY_EVALUATIONS_TAB) }}
|
||||
<tab-counter :count="state.value?.evaluations?.count || 0" />
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
@@ -54,9 +56,12 @@
|
||||
:class="{ active: activeTab === 'MyTasks' }"
|
||||
@click="selectTab('MyTasks')"
|
||||
>
|
||||
{{ $t("my_tasks.tab") }}
|
||||
{{ trans(MY_TASKS_TAB) }}
|
||||
<tab-counter
|
||||
:count="state.tasks.warning.count + state.tasks.alert.count"
|
||||
:count="
|
||||
(state.value?.tasks?.warning?.count || 0) +
|
||||
(state.value?.tasks?.alert?.count || 0)
|
||||
"
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
@@ -66,19 +71,25 @@
|
||||
:class="{ active: activeTab === 'MyWorkflows' }"
|
||||
@click="selectTab('MyWorkflows')"
|
||||
>
|
||||
{{ $t("my_workflows.tab") }}
|
||||
<tab-counter :count="state.workflows.count + state.workflowsCc.count" />
|
||||
{{ trans(MY_WORKFLOWS_TAB) }}
|
||||
<tab-counter
|
||||
:count="
|
||||
(state.value?.workflows?.count || 0) +
|
||||
(state.value?.workflowsCc?.count || 0)
|
||||
"
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item loading ms-auto py-2" v-if="loading">
|
||||
<i
|
||||
class="fa fa-circle-o-notch fa-spin fa-lg text-chill-gray"
|
||||
:title="$t('loading')"
|
||||
:title="trans(LOADING)"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="my-4">
|
||||
<my-tickets v-if="activeTab == 'MyTickets'" />
|
||||
<my-customs v-if="activeTab === 'MyCustoms'" />
|
||||
<my-works v-else-if="activeTab === 'MyWorks'" />
|
||||
<my-evaluations v-else-if="activeTab === 'MyEvaluations'" />
|
||||
@@ -91,63 +102,58 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MyCustoms from "./MyCustoms";
|
||||
import MyWorks from "./MyWorks";
|
||||
import MyEvaluations from "./MyEvaluations";
|
||||
import MyTasks from "./MyTasks";
|
||||
import MyAccompanyingCourses from "./MyAccompanyingCourses";
|
||||
import MyNotifications from "./MyNotifications";
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import MyCustoms from "./MyCustoms.vue";
|
||||
import MyWorks from "./MyWorks.vue";
|
||||
import MyEvaluations from "./MyEvaluations.vue";
|
||||
import MyTasks from "./MyTasks.vue";
|
||||
import MyAccompanyingCourses from "./MyAccompanyingCourses.vue";
|
||||
import MyNotifications from "./MyNotifications.vue";
|
||||
import MyWorkflows from "./MyWorkflows.vue";
|
||||
import TabCounter from "./TabCounter";
|
||||
import { mapState } from "vuex";
|
||||
import MyTickets from "./MyTickets.vue";
|
||||
import TabCounter from "./TabCounter.vue";
|
||||
import {
|
||||
MAIN_TITLE,
|
||||
MY_TICKETS_TAB,
|
||||
MY_EVALUATIONS_TAB,
|
||||
MY_TASKS_TAB,
|
||||
MY_ACCOMPANYING_COURSES_TAB,
|
||||
MY_NOTIFICATIONS_TAB,
|
||||
MY_WORKFLOWS_TAB,
|
||||
LOADING,
|
||||
trans,
|
||||
} from "translator";
|
||||
const store = useStore();
|
||||
|
||||
export default {
|
||||
name: "App",
|
||||
components: {
|
||||
MyCustoms,
|
||||
MyWorks,
|
||||
MyEvaluations,
|
||||
MyTasks,
|
||||
MyWorkflows,
|
||||
MyAccompanyingCourses,
|
||||
MyNotifications,
|
||||
TabCounter,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeTab: "MyCustoms",
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(["loading"]),
|
||||
// just to see all in devtool :
|
||||
...mapState({
|
||||
state: (state) => state,
|
||||
}),
|
||||
},
|
||||
methods: {
|
||||
selectTab(tab) {
|
||||
if (tab !== "MyCustoms") {
|
||||
this.$store.dispatch("getByTab", { tab: tab });
|
||||
}
|
||||
this.activeTab = tab;
|
||||
console.log(this.activeTab);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
for (const m of [
|
||||
"MyNotifications",
|
||||
"MyAccompanyingCourses",
|
||||
// 'MyWorks',
|
||||
"MyEvaluations",
|
||||
"MyTasks",
|
||||
"MyWorkflows",
|
||||
]) {
|
||||
this.$store.dispatch("getByTab", { tab: m, param: "countOnly=1" });
|
||||
}
|
||||
},
|
||||
};
|
||||
const activeTab = ref("MyCustoms");
|
||||
|
||||
const loading = computed(() => store.state.loading);
|
||||
|
||||
const state = computed(() => store.state.homepage);
|
||||
const ticketListState = computed(() => store.state.ticketList);
|
||||
|
||||
function selectTab(tab: string) {
|
||||
if (tab !== "MyCustoms") {
|
||||
store.dispatch("getByTab", { tab: tab });
|
||||
}
|
||||
activeTab.value = tab;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
for (const m of [
|
||||
"MyTickets",
|
||||
"MyNotifications",
|
||||
"MyAccompanyingCourses",
|
||||
// 'MyWorks',
|
||||
"MyEvaluations",
|
||||
"MyTasks",
|
||||
"MyWorkflows",
|
||||
]) {
|
||||
store.dispatch("getByTab", { tab: m, param: "countOnly=1" });
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@@ -1,35 +1,35 @@
|
||||
<template>
|
||||
<div class="alert alert-light">
|
||||
{{ $t("my_accompanying_courses.description") }}
|
||||
{{ trans(MY_ACCOMPANYING_COURSES_DESCRIPTION) }}
|
||||
</div>
|
||||
<span v-if="noResults" class="chill-no-data-statement">{{
|
||||
$t("no_data")
|
||||
}}</span>
|
||||
<span v-if="noResults" class="chill-no-data-statement">
|
||||
{{ trans(NO_DATA) }}
|
||||
</span>
|
||||
<tab-table v-else>
|
||||
<template #thead>
|
||||
<th scope="col">
|
||||
{{ $t("opening_date") }}
|
||||
{{ trans(OPENING_DATE) }}
|
||||
</th>
|
||||
<th scope="col">
|
||||
{{ $t("social_issues") }}
|
||||
{{ trans(SOCIAL_ISSUES) }}
|
||||
</th>
|
||||
<th scope="col">
|
||||
{{ $t("concerned_persons") }}
|
||||
{{ trans(CONCERNED_PERSONS) }}
|
||||
</th>
|
||||
<th scope="col" />
|
||||
<th scope="col" />
|
||||
</template>
|
||||
<template #tbody>
|
||||
<tr v-for="(c, i) in accompanyingCourses.results" :key="`course-${i}`">
|
||||
<td>{{ $d(c.openingDate.datetime, "short") }}</td>
|
||||
<td>{{ $d(new Date(c.openingDate.datetime), "short") }}</td>
|
||||
<td>
|
||||
<span
|
||||
v-for="(i, index) in c.socialIssues"
|
||||
v-for="(issue, index) in c.socialIssues"
|
||||
:key="index"
|
||||
class="chill-entity entity-social-issue"
|
||||
>
|
||||
<span class="badge bg-chill-l-gray text-dark">
|
||||
{{ localizeString(i.title) }}
|
||||
{{ localizeString(issue.title) }}
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
@@ -46,15 +46,15 @@
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="c.emergency" class="badge rounded-pill bg-danger me-1">{{
|
||||
$t("emergency")
|
||||
trans(EMERGENCY)
|
||||
}}</span>
|
||||
<span v-if="c.confidential" class="badge rounded-pill bg-danger">{{
|
||||
$t("confidential")
|
||||
trans(CONFIDENTIAL)
|
||||
}}</span>
|
||||
</td>
|
||||
<td>
|
||||
<a class="btn btn-sm btn-show" :href="getUrl(c)">
|
||||
{{ $t("show_entity", { entity: $t("the_course") }) }}
|
||||
{{ trans(SHOW_ENTITY, { entity: trans(THE_COURSE) }) }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -62,36 +62,45 @@
|
||||
</tab-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapGetters } from "vuex";
|
||||
import TabTable from "./TabTable";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly";
|
||||
<script lang="ts" setup>
|
||||
import { computed, ComputedRef } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import TabTable from "./TabTable.vue";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
||||
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
||||
import { AccompanyingCourse } from "ChillPersonAssets/types";
|
||||
import { PaginationResponse } from "ChillMainAssets/lib/api/apiMethods";
|
||||
import {
|
||||
MY_ACCOMPANYING_COURSES_DESCRIPTION,
|
||||
OPENING_DATE,
|
||||
SOCIAL_ISSUES,
|
||||
CONCERNED_PERSONS,
|
||||
SHOW_ENTITY,
|
||||
THE_COURSE,
|
||||
NO_DATA,
|
||||
EMERGENCY,
|
||||
CONFIDENTIAL,
|
||||
trans,
|
||||
} from "translator";
|
||||
const store = useStore();
|
||||
|
||||
export default {
|
||||
name: "MyAccompanyingCourses",
|
||||
components: {
|
||||
TabTable,
|
||||
OnTheFly,
|
||||
},
|
||||
computed: {
|
||||
...mapState(["accompanyingCourses"]),
|
||||
...mapGetters(["isAccompanyingCoursesLoaded"]),
|
||||
noResults() {
|
||||
if (!this.isAccompanyingCoursesLoaded) {
|
||||
return false;
|
||||
} else {
|
||||
return this.accompanyingCourses.count === 0;
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
localizeString,
|
||||
getUrl(c) {
|
||||
return `/fr/parcours/${c.id}`;
|
||||
},
|
||||
},
|
||||
};
|
||||
const accompanyingCourses: ComputedRef<PaginationResponse<AccompanyingCourse>> =
|
||||
computed(() => store.state.homepage.accompanyingCourses);
|
||||
const isAccompanyingCoursesLoaded = computed(
|
||||
() => store.getters.isAccompanyingCoursesLoaded,
|
||||
);
|
||||
|
||||
const noResults = computed(() => {
|
||||
if (!isAccompanyingCoursesLoaded.value) {
|
||||
return false;
|
||||
} else {
|
||||
return accompanyingCourses.value.count === 0;
|
||||
}
|
||||
});
|
||||
|
||||
function getUrl(c: { id: number }): string {
|
||||
return `/fr/parcours/${c.id}`;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@@ -1,93 +1,72 @@
|
||||
<template>
|
||||
<span v-if="noResults" class="chill-no-data-statement">{{
|
||||
$t("no_dashboard")
|
||||
}}</span>
|
||||
<span v-if="noResults" class="chill-no-data-statement">
|
||||
{{ trans(NO_DASHBOARD) }}
|
||||
</span>
|
||||
<div v-else id="dashboards" class="container g-3">
|
||||
<div class="row">
|
||||
<div class="mbloc col-xs-12 col-sm-4">
|
||||
<div class="custom1">
|
||||
<ul class="list-unstyled">
|
||||
<li v-if="counter.notifications > 0">
|
||||
<i18n-t
|
||||
keypath="counter.unread_notifications"
|
||||
tag="span"
|
||||
:class="counterClass"
|
||||
:plural="counter.notifications"
|
||||
>
|
||||
<template #n>
|
||||
<span>{{ counter.notifications }}</span>
|
||||
</template>
|
||||
</i18n-t>
|
||||
<li v-if="(counter.value?.notifications || 0) > 0">
|
||||
<span :class="counterClass">
|
||||
{{
|
||||
trans(COUNTER_UNREAD_NOTIFICATIONS, {
|
||||
n: counter.value?.notifications || 0,
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="counter.accompanyingCourses > 0">
|
||||
<i18n-t
|
||||
keypath="counter.assignated_courses"
|
||||
tag="span"
|
||||
:class="counterClass"
|
||||
:plural="counter.accompanyingCourses"
|
||||
>
|
||||
<template #n>
|
||||
<span>{{ counter.accompanyingCourses }}</span>
|
||||
</template>
|
||||
</i18n-t>
|
||||
<li v-if="(counter.value?.accompanyingCourses || 0) > 0">
|
||||
<span :class="counterClass">
|
||||
{{
|
||||
trans(COUNTER_ASSIGNATED_COURSES, {
|
||||
n: counter.value?.accompanyingCourses || 0,
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="counter.works > 0">
|
||||
<i18n-t
|
||||
keypath="counter.assignated_actions"
|
||||
tag="span"
|
||||
:class="counterClass"
|
||||
:plural="counter.works"
|
||||
>
|
||||
<template #n>
|
||||
<span>{{ counter.works }}</span>
|
||||
</template>
|
||||
</i18n-t>
|
||||
<li v-if="(counter.value?.works || 0) > 0">
|
||||
<span :class="counterClass">
|
||||
{{
|
||||
trans(COUNTER_ASSIGNATED_ACTIONS, {
|
||||
n: counter.value?.works || 0,
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="counter.evaluations > 0">
|
||||
<i18n-t
|
||||
keypath="counter.assignated_evaluations"
|
||||
tag="span"
|
||||
:class="counterClass"
|
||||
:plural="counter.evaluations"
|
||||
>
|
||||
<template #n>
|
||||
<span>{{ counter.evaluations }}</span>
|
||||
</template>
|
||||
</i18n-t>
|
||||
<li v-if="(counter.value?.evaluations || 0) > 0">
|
||||
<span :class="counterClass">
|
||||
{{
|
||||
trans(COUNTER_ASSIGNATED_EVALUATIONS, {
|
||||
n: counter.value?.evaluations || 0,
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="counter.tasksAlert > 0">
|
||||
<i18n-t
|
||||
keypath="counter.alert_tasks"
|
||||
tag="span"
|
||||
:class="counterClass"
|
||||
:plural="counter.tasksAlert"
|
||||
>
|
||||
<template #n>
|
||||
<span>{{ counter.tasksAlert }}</span>
|
||||
</template>
|
||||
</i18n-t>
|
||||
<li v-if="(counter.value?.tasksAlert || 0) > 0">
|
||||
<span :class="counterClass">
|
||||
{{
|
||||
trans(COUNTER_ALERT_TASKS, {
|
||||
n: counter.value?.tasksAlert || 0,
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="counter.tasksWarning > 0">
|
||||
<i18n-t
|
||||
keypath="counter.warning_tasks"
|
||||
tag="span"
|
||||
:class="counterClass"
|
||||
:plural="counter.tasksWarning"
|
||||
>
|
||||
<template #n>
|
||||
<span>{{ counter.tasksWarning }}</span>
|
||||
</template>
|
||||
</i18n-t>
|
||||
<li v-if="(counter.value?.tasksWarning || 0) > 0">
|
||||
<span :class="counterClass">
|
||||
{{
|
||||
trans(COUNTER_WARNING_TASKS, {
|
||||
n: counter.value?.tasksWarning || 0,
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template v-if="this.hasDashboardItems">
|
||||
<template
|
||||
v-for="(dashboardItem, index) in this.dashboardItems"
|
||||
:key="index"
|
||||
>
|
||||
<template v-if="hasDashboardItems">
|
||||
<template v-for="(dashboardItem, index) in dashboardItems" :key="index">
|
||||
<div
|
||||
class="mbloc col-xs-12 col-sm-8 news"
|
||||
v-if="dashboardItem.type === 'news'"
|
||||
@@ -100,44 +79,53 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from "vuex";
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
|
||||
import News from "./DashboardWidgets/News.vue";
|
||||
import {
|
||||
NO_DASHBOARD,
|
||||
COUNTER_UNREAD_NOTIFICATIONS,
|
||||
COUNTER_ASSIGNATED_COURSES,
|
||||
COUNTER_ASSIGNATED_ACTIONS,
|
||||
COUNTER_ASSIGNATED_EVALUATIONS,
|
||||
COUNTER_ALERT_TASKS,
|
||||
COUNTER_WARNING_TASKS,
|
||||
trans,
|
||||
} from "translator";
|
||||
|
||||
export default {
|
||||
name: "MyCustoms",
|
||||
components: {
|
||||
News,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
counterClass: {
|
||||
counter: true, //hack to pass class 'counter' in i18n-t
|
||||
},
|
||||
dashboardItems: [],
|
||||
masonry: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["counter"]),
|
||||
noResults() {
|
||||
return false;
|
||||
},
|
||||
hasDashboardItems() {
|
||||
return this.dashboardItems.length > 0;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
makeFetch("GET", "/api/1.0/main/dashboard-config-item.json")
|
||||
.then((response) => {
|
||||
this.dashboardItems = response;
|
||||
})
|
||||
.catch((error) => {
|
||||
throw error;
|
||||
});
|
||||
},
|
||||
};
|
||||
interface MyCustom {
|
||||
id: number;
|
||||
type: string;
|
||||
metadata: Record<string, unknown>;
|
||||
userId: number;
|
||||
position: string;
|
||||
}
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const counter = computed(() => store.getters.counter);
|
||||
|
||||
const counterClass = { counter: true };
|
||||
|
||||
const dashboardItems = ref<MyCustom[]>([]);
|
||||
|
||||
const noResults = computed(() => false);
|
||||
|
||||
const hasDashboardItems = computed(() => dashboardItems.value.length > 0);
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const response: MyCustom[] = await makeFetch(
|
||||
"GET",
|
||||
"/api/1.0/main/dashboard-config-item.json",
|
||||
);
|
||||
dashboardItems.value = response;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@@ -1,44 +1,50 @@
|
||||
<template>
|
||||
<div class="accompanying-course-work">
|
||||
<div class="alert alert-light">
|
||||
{{ $t("my_evaluations.description") }}
|
||||
{{ trans(MY_EVALUATIONS_DESCRIPTION) }}
|
||||
</div>
|
||||
<span v-if="noResults" class="chill-no-data-statement">{{
|
||||
$t("no_data")
|
||||
}}</span>
|
||||
<span v-if="noResults" class="chill-no-data-statement">
|
||||
{{ trans(NO_DATA) }}
|
||||
</span>
|
||||
<tab-table v-else>
|
||||
<template #thead>
|
||||
<th scope="col">
|
||||
{{ $t("max_date") }}
|
||||
{{ trans(MAX_DATE) }}
|
||||
</th>
|
||||
<th scope="col">
|
||||
{{ $t("evaluation") }}
|
||||
{{ trans(EVALUATION) }}
|
||||
</th>
|
||||
<th scope="col">
|
||||
{{ $t("SocialAction") }}
|
||||
{{ trans(SOCIAL_ACTION) }}
|
||||
</th>
|
||||
<th scope="col" />
|
||||
</template>
|
||||
<template #tbody>
|
||||
<tr v-for="(e, i) in evaluations.results" :key="`evaluation-${i}`">
|
||||
<td>{{ $d(e.maxDate.datetime, "short") }}</td>
|
||||
<td>
|
||||
{{ localizeString(e.evaluation.title) }}
|
||||
{{
|
||||
e.maxDate?.datetime
|
||||
? $d(new Date(e.maxDate.datetime), "short")
|
||||
: ""
|
||||
}}
|
||||
</td>
|
||||
<td>
|
||||
{{ localizeString(e.evaluation?.title ?? null) }}
|
||||
</td>
|
||||
<td>
|
||||
<span class="chill-entity entity-social-issue">
|
||||
<span class="badge bg-chill-l-gray text-dark">
|
||||
{{ e.accompanyingPeriodWork.socialAction.issue.text }}
|
||||
{{ e.accompanyingPeriodWork?.socialAction?.issue?.text ?? "" }}
|
||||
</span>
|
||||
</span>
|
||||
<h4 class="badge-title">
|
||||
<span class="title_label" />
|
||||
<span class="title_action">
|
||||
{{ e.accompanyingPeriodWork.socialAction.text }}
|
||||
{{ e.accompanyingPeriodWork?.socialAction?.text ?? "" }}
|
||||
</span>
|
||||
</h4>
|
||||
<span
|
||||
v-for="person in e.accompanyingPeriodWork.persons"
|
||||
v-for="person in e.accompanyingPeriodWork?.persons ?? []"
|
||||
class="me-1"
|
||||
:key="person.id"
|
||||
>
|
||||
@@ -55,18 +61,22 @@
|
||||
<div class="btn-group-vertical" role="group" aria-label="Actions">
|
||||
<a class="btn btn-sm btn-show" :href="getUrl(e)">
|
||||
{{
|
||||
$t("show_entity", {
|
||||
entity: $t("the_evaluation"),
|
||||
trans(SHOW_ENTITY, {
|
||||
entity: trans(THE_EVALUATION),
|
||||
})
|
||||
}}
|
||||
</a>
|
||||
<a
|
||||
class="btn btn-sm btn-show"
|
||||
:href="getUrl(e.accompanyingPeriodWork.accompanyingPeriod)"
|
||||
:href="getUrl(e.accompanyingPeriodWork.accompanyingPeriod!)"
|
||||
v-if="
|
||||
e.accompanyingPeriodWork &&
|
||||
e.accompanyingPeriodWork.accompanyingPeriod
|
||||
"
|
||||
>
|
||||
{{
|
||||
$t("show_entity", {
|
||||
entity: $t("the_course"),
|
||||
trans(SHOW_ENTITY, {
|
||||
entity: trans(THE_COURSE),
|
||||
})
|
||||
}}
|
||||
</a>
|
||||
@@ -78,46 +88,70 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapGetters } from "vuex";
|
||||
import TabTable from "./TabTable";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly";
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import TabTable from "./TabTable.vue";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
||||
import { localizeString } from "../../lib/localizationHelper/localizationHelper";
|
||||
|
||||
export default {
|
||||
name: "MyEvaluations",
|
||||
components: {
|
||||
TabTable,
|
||||
OnTheFly,
|
||||
},
|
||||
computed: {
|
||||
...mapState(["evaluations"]),
|
||||
...mapGetters(["isEvaluationsLoaded"]),
|
||||
noResults() {
|
||||
if (!this.isEvaluationsLoaded) {
|
||||
return false;
|
||||
} else {
|
||||
return this.evaluations.count === 0;
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
localizeString,
|
||||
getUrl(e) {
|
||||
switch (e.type) {
|
||||
case "accompanying_period_work_evaluation":
|
||||
let anchor = "#evaluations";
|
||||
return `/fr/person/accompanying-period/work/${e.accompanyingPeriodWork.id}/edit${anchor}`;
|
||||
case "accompanying_period_work":
|
||||
return `/fr/person/accompanying-period/work/${e.id}/edit`;
|
||||
case "accompanying_period":
|
||||
return `/fr/parcours/${e.id}`;
|
||||
default:
|
||||
throw "entity type unknown";
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
const store = useStore();
|
||||
|
||||
import type { ComputedRef } from "vue";
|
||||
import {
|
||||
AccompanyingPeriod,
|
||||
AccompanyingPeriodWorkEvaluation,
|
||||
AccompanyingPeriodWork,
|
||||
} from "ChillPersonAssets/types";
|
||||
import { PaginationResponse } from "ChillMainAssets/lib/api/apiMethods";
|
||||
import {
|
||||
MY_EVALUATIONS_DESCRIPTION,
|
||||
MAX_DATE,
|
||||
EVALUATION,
|
||||
SHOW_ENTITY,
|
||||
THE_COURSE,
|
||||
THE_EVALUATION,
|
||||
SOCIAL_ACTION,
|
||||
NO_DATA,
|
||||
trans,
|
||||
} from "translator";
|
||||
const evaluations: ComputedRef<
|
||||
PaginationResponse<AccompanyingPeriodWorkEvaluation>
|
||||
> = computed(() => store.state.homepage.evaluations);
|
||||
const isEvaluationsLoaded = computed(() => store.getters.isEvaluationsLoaded);
|
||||
|
||||
const noResults = computed(() => {
|
||||
if (!isEvaluationsLoaded.value) {
|
||||
return false;
|
||||
} else {
|
||||
return evaluations.value.count === 0;
|
||||
}
|
||||
});
|
||||
|
||||
function getUrl(
|
||||
e:
|
||||
| AccompanyingPeriodWorkEvaluation
|
||||
| AccompanyingPeriod
|
||||
| AccompanyingPeriodWork,
|
||||
): string {
|
||||
if (!e) {
|
||||
throw "entity is undefined";
|
||||
}
|
||||
|
||||
if ("type" in e && typeof e.type === "string") {
|
||||
switch (e.type) {
|
||||
case "accompanying_period_work_evaluation":
|
||||
return `/fr/person/accompanying-period/work/${e.accompanyingPeriodWork?.id}/edit#evaluations`;
|
||||
case "accompanying_period_work":
|
||||
return `/fr/person/accompanying-period/work/${e.id}/edit`;
|
||||
case "accompanying_period":
|
||||
return `/fr/parcours/${e.id}`;
|
||||
default:
|
||||
throw "entity type unknown";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
@@ -1,26 +1,26 @@
|
||||
<template>
|
||||
<div class="alert alert-light">
|
||||
{{ $t("my_notifications.description") }}
|
||||
{{ trans(MY_NOTIFICATIONS_DESCRIPTION) }}
|
||||
</div>
|
||||
<span v-if="noResults" class="chill-no-data-statement">{{
|
||||
$t("no_data")
|
||||
}}</span>
|
||||
<span v-if="noResults" class="chill-no-data-statement">
|
||||
{{ trans(NO_DATA) }}
|
||||
</span>
|
||||
<tab-table v-else>
|
||||
<template #thead>
|
||||
<th scope="col">
|
||||
{{ $t("Date") }}
|
||||
{{ trans(DATE) }}
|
||||
</th>
|
||||
<th scope="col">
|
||||
{{ $t("Subject") }}
|
||||
{{ trans(SUBJECT) }}
|
||||
</th>
|
||||
<th scope="col">
|
||||
{{ $t("From") }}
|
||||
{{ trans(FROM) }}
|
||||
</th>
|
||||
<th scope="col" />
|
||||
</template>
|
||||
<template #tbody>
|
||||
<tr v-for="(n, i) in notifications.results" :key="`notify-${i}`">
|
||||
<td>{{ $d(n.date.datetime, "long") }}</td>
|
||||
<td>{{ $d(new Date(n.date.datetime), "long") }}</td>
|
||||
<td>
|
||||
<span class="unread">
|
||||
<i class="fa fa-envelope-o" />
|
||||
@@ -31,11 +31,11 @@
|
||||
{{ n.sender.text }}
|
||||
</td>
|
||||
<td v-else>
|
||||
{{ $t("automatic_notification") }}
|
||||
{{ trans(AUTOMATIC_NOTIFICATION) }}
|
||||
</td>
|
||||
<td>
|
||||
<a class="btn btn-sm btn-show" :href="getEntityUrl(n)">
|
||||
{{ $t("show_entity", { entity: getEntityName(n) }) }}
|
||||
{{ trans(SHOW_ENTITY, { entity: getEntityName(n) }) }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -43,65 +43,82 @@
|
||||
</tab-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapGetters } from "vuex";
|
||||
import TabTable from "./TabTable";
|
||||
import { appMessages } from "ChillMainAssets/vuejs/HomepageWidget/js/i18n";
|
||||
<script lang="ts" setup>
|
||||
import { computed, ComputedRef } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import TabTable from "./TabTable.vue";
|
||||
import { Notification } from "ChillPersonAssets/types";
|
||||
|
||||
export default {
|
||||
name: "MyNotifications",
|
||||
components: {
|
||||
TabTable,
|
||||
},
|
||||
computed: {
|
||||
...mapState(["notifications"]),
|
||||
...mapGetters(["isNotificationsLoaded"]),
|
||||
noResults() {
|
||||
if (!this.isNotificationsLoaded) {
|
||||
return false;
|
||||
} else {
|
||||
return this.notifications.count === 0;
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getNotificationUrl(n) {
|
||||
return `/fr/notification/${n.id}/show`;
|
||||
},
|
||||
getEntityName(n) {
|
||||
switch (n.relatedEntityClass) {
|
||||
case "Chill\\ActivityBundle\\Entity\\Activity":
|
||||
return appMessages.fr.the_activity;
|
||||
case "Chill\\PersonBundle\\Entity\\AccompanyingPeriod":
|
||||
return appMessages.fr.the_course;
|
||||
case "Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWork":
|
||||
return appMessages.fr.the_action;
|
||||
case "Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluationDocument":
|
||||
return appMessages.fr.the_evaluation_document;
|
||||
case "Chill\\MainBundle\\Entity\\Workflow\\EntityWorkflow":
|
||||
return appMessages.fr.the_workflow;
|
||||
default:
|
||||
throw "notification type unknown";
|
||||
}
|
||||
},
|
||||
getEntityUrl(n) {
|
||||
switch (n.relatedEntityClass) {
|
||||
case "Chill\\ActivityBundle\\Entity\\Activity":
|
||||
return `/fr/activity/${n.relatedEntityId}/show`;
|
||||
case "Chill\\PersonBundle\\Entity\\AccompanyingPeriod":
|
||||
return `/fr/parcours/${n.relatedEntityId}`;
|
||||
case "Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWork":
|
||||
return `/fr/person/accompanying-period/work/${n.relatedEntityId}/show`;
|
||||
case "Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluationDocument":
|
||||
return `/fr/person/accompanying-period/work/evaluation/document/${n.relatedEntityId}/show`;
|
||||
case "Chill\\MainBundle\\Entity\\Workflow\\EntityWorkflow":
|
||||
return `/fr/main/workflow/${n.relatedEntityId}/show`;
|
||||
default:
|
||||
throw "notification type unknown";
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
import {
|
||||
MY_NOTIFICATIONS_DESCRIPTION,
|
||||
DATE,
|
||||
FROM,
|
||||
SUBJECT,
|
||||
SHOW_ENTITY,
|
||||
THE_ACTIVITY,
|
||||
THE_COURSE,
|
||||
THE_ACTION,
|
||||
THE_EVALUATION_DOCUMENT,
|
||||
THE_WORKFLOW,
|
||||
NO_DATA,
|
||||
AUTOMATIC_NOTIFICATION,
|
||||
trans,
|
||||
} from "translator";
|
||||
import { PaginationResponse } from "ChillMainAssets/lib/api/apiMethods";
|
||||
const store = useStore();
|
||||
|
||||
const notifications: ComputedRef<PaginationResponse<Notification>> = computed(
|
||||
() => store.state.homepage.notifications,
|
||||
);
|
||||
const isNotificationsLoaded = computed(
|
||||
() => store.getters.isNotificationsLoaded,
|
||||
);
|
||||
|
||||
const noResults = computed(() => {
|
||||
if (!isNotificationsLoaded.value) {
|
||||
return false;
|
||||
} else {
|
||||
return notifications.value.count === 0;
|
||||
}
|
||||
});
|
||||
|
||||
function getNotificationUrl(n: Notification): string {
|
||||
return `/fr/notification/${n.id}/show`;
|
||||
}
|
||||
|
||||
function getEntityName(n: Notification): string {
|
||||
switch (n.relatedEntityClass) {
|
||||
case "Chill\\ActivityBundle\\Entity\\Activity":
|
||||
return trans(THE_ACTIVITY);
|
||||
case "Chill\\PersonBundle\\Entity\\AccompanyingPeriod":
|
||||
return trans(THE_COURSE);
|
||||
case "Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWork":
|
||||
return trans(THE_ACTION);
|
||||
case "Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluationDocument":
|
||||
return trans(THE_EVALUATION_DOCUMENT);
|
||||
case "Chill\\MainBundle\\Entity\\Workflow\\EntityWorkflow":
|
||||
return trans(THE_WORKFLOW);
|
||||
default:
|
||||
throw "notification type unknown";
|
||||
}
|
||||
}
|
||||
|
||||
function getEntityUrl(n: Notification): string {
|
||||
switch (n.relatedEntityClass) {
|
||||
case "Chill\\ActivityBundle\\Entity\\Activity":
|
||||
return `/fr/activity/${n.relatedEntityId}/show`;
|
||||
case "Chill\\PersonBundle\\Entity\\AccompanyingPeriod":
|
||||
return `/fr/parcours/${n.relatedEntityId}`;
|
||||
case "Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWork":
|
||||
return `/fr/person/accompanying-period/work/${n.relatedEntityId}/show`;
|
||||
case "Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluationDocument":
|
||||
return `/fr/person/accompanying-period/work/evaluation/document/${n.relatedEntityId}/show`;
|
||||
case "Chill\\MainBundle\\Entity\\Workflow\\EntityWorkflow":
|
||||
return `/fr/main/workflow/${n.relatedEntityId}/show`;
|
||||
default:
|
||||
throw "notification type unknown";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@@ -1,36 +1,38 @@
|
||||
<template>
|
||||
<div class="alert alert-light">
|
||||
{{ $t("my_tasks.description_warning") }}
|
||||
{{ trans(MY_TASKS_DESCRIPTION_WARNING) }}
|
||||
</div>
|
||||
<span v-if="noResultsAlert" class="chill-no-data-statement">{{
|
||||
$t("no_data")
|
||||
}}</span>
|
||||
<span v-if="noResultsAlert" class="chill-no-data-statement">
|
||||
{{ trans(NO_DATA) }}
|
||||
</span>
|
||||
<tab-table v-else>
|
||||
<template #thead>
|
||||
<th scope="col">
|
||||
{{ $t("warning_date") }}
|
||||
{{ trans(WARNING_DATE) }}
|
||||
</th>
|
||||
<th scope="col">
|
||||
{{ $t("max_date") }}
|
||||
{{ trans(MAX_DATE) }}
|
||||
</th>
|
||||
<th scope="col">
|
||||
{{ $t("task") }}
|
||||
{{ trans(TASK) }}
|
||||
</th>
|
||||
<th scope="col" />
|
||||
</template>
|
||||
<template #tbody>
|
||||
<tr v-for="(t, i) in tasks.alert.results" :key="`task-alert-${i}`">
|
||||
<td v-if="null !== t.warningDate">
|
||||
{{ $d(t.warningDate.datetime, "short") }}
|
||||
<td v-if="t.warningDate !== null">
|
||||
{{ $d(new Date(t.warningDate.datetime), "short") }}
|
||||
</td>
|
||||
<td v-else />
|
||||
<td>
|
||||
<span class="outdated">{{ $d(t.endDate.datetime, "short") }}</span>
|
||||
<span class="outdated">{{
|
||||
$d(new Date(t.endDate.datetime), "short")
|
||||
}}</span>
|
||||
</td>
|
||||
<td>{{ t.title }}</td>
|
||||
<td>
|
||||
<a class="btn btn-sm btn-show" :href="getUrl(t)">
|
||||
{{ $t("show_entity", { entity: $t("the_task") }) }}
|
||||
{{ trans(SHOW_ENTITY, { entity: trans(THE_TASK) }) }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -38,21 +40,21 @@
|
||||
</tab-table>
|
||||
|
||||
<div class="alert alert-light">
|
||||
{{ $t("my_tasks.description_alert") }}
|
||||
{{ trans(MY_TASKS_DESCRIPTION_ALERT) }}
|
||||
</div>
|
||||
<span v-if="noResultsWarning" class="chill-no-data-statement">{{
|
||||
$t("no_data")
|
||||
}}</span>
|
||||
<span v-if="noResultsWarning" class="chill-no-data-statement">
|
||||
{{ trans(NO_DATA) }}
|
||||
</span>
|
||||
<tab-table v-else>
|
||||
<template #thead>
|
||||
<th scope="col">
|
||||
{{ $t("warning_date") }}
|
||||
{{ trans(WARNING_DATE) }}
|
||||
</th>
|
||||
<th scope="col">
|
||||
{{ $t("max_date") }}
|
||||
{{ trans(MAX_DATE) }}
|
||||
</th>
|
||||
<th scope="col">
|
||||
{{ $t("task") }}
|
||||
{{ trans(TASK) }}
|
||||
</th>
|
||||
<th scope="col" />
|
||||
</template>
|
||||
@@ -60,14 +62,14 @@
|
||||
<tr v-for="(t, i) in tasks.warning.results" :key="`task-warning-${i}`">
|
||||
<td>
|
||||
<span class="outdated">{{
|
||||
$d(t.warningDate.datetime, "short")
|
||||
$d(new Date(t.warningDate.datetime), "short")
|
||||
}}</span>
|
||||
</td>
|
||||
<td>{{ $d(t.endDate.datetime, "short") }}</td>
|
||||
<td>{{ $d(new Date(t.endDate.datetime), "short") }}</td>
|
||||
<td>{{ t.title }}</td>
|
||||
<td>
|
||||
<a class="btn btn-sm btn-show" :href="getUrl(t)">
|
||||
{{ $t("show_entity", { entity: $t("the_task") }) }}
|
||||
{{ trans(SHOW_ENTITY, { entity: trans(THE_TASK) }) }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -75,39 +77,51 @@
|
||||
</tab-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapGetters } from "vuex";
|
||||
import TabTable from "./TabTable";
|
||||
<script lang="ts" setup>
|
||||
import { computed, ComputedRef } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import TabTable from "./TabTable.vue";
|
||||
import {
|
||||
MY_TASKS_DESCRIPTION_ALERT,
|
||||
MY_TASKS_DESCRIPTION_WARNING,
|
||||
MAX_DATE,
|
||||
WARNING_DATE,
|
||||
TASK,
|
||||
SHOW_ENTITY,
|
||||
THE_TASK,
|
||||
NO_DATA,
|
||||
trans,
|
||||
} from "translator";
|
||||
import { TasksState } from "./store/modules/homepage";
|
||||
import { Alert, Warning } from "ChillPersonAssets/types";
|
||||
|
||||
export default {
|
||||
name: "MyTasks",
|
||||
components: {
|
||||
TabTable,
|
||||
},
|
||||
computed: {
|
||||
...mapState(["tasks"]),
|
||||
...mapGetters(["isTasksWarningLoaded", "isTasksAlertLoaded"]),
|
||||
noResultsAlert() {
|
||||
if (!this.isTasksAlertLoaded) {
|
||||
return false;
|
||||
} else {
|
||||
return this.tasks.alert.count === 0;
|
||||
}
|
||||
},
|
||||
noResultsWarning() {
|
||||
if (!this.isTasksWarningLoaded) {
|
||||
return false;
|
||||
} else {
|
||||
return this.tasks.warning.count === 0;
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getUrl(t) {
|
||||
return `/fr/task/single-task/${t.id}/show`;
|
||||
},
|
||||
},
|
||||
};
|
||||
const store = useStore();
|
||||
|
||||
const tasks: ComputedRef<TasksState> = computed(
|
||||
() => store.state.homepage.tasks,
|
||||
);
|
||||
const isTasksWarningLoaded = computed(() => store.getters.isTasksWarningLoaded);
|
||||
const isTasksAlertLoaded = computed(() => store.getters.isTasksAlertLoaded);
|
||||
|
||||
const noResultsAlert = computed(() => {
|
||||
if (!isTasksAlertLoaded.value) {
|
||||
return false;
|
||||
} else {
|
||||
return tasks.value.alert.count === 0;
|
||||
}
|
||||
});
|
||||
|
||||
const noResultsWarning = computed(() => {
|
||||
if (!isTasksWarningLoaded.value) {
|
||||
return false;
|
||||
} else {
|
||||
return tasks.value.warning.count === 0;
|
||||
}
|
||||
});
|
||||
|
||||
function getUrl(t: Warning | Alert): string {
|
||||
return `/fr/task/single-task/${t.id}/show`;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<div class="col-12">
|
||||
<!-- Loading state -->
|
||||
<div
|
||||
v-if="isTicketLoading"
|
||||
class="d-flex justify-content-center align-items-center"
|
||||
style="height: 200px"
|
||||
>
|
||||
<div class="text-center">
|
||||
<div class="spinner-border mb-3" role="status">
|
||||
<span class="visually-hidden">{{
|
||||
trans(CHILL_TICKET_LIST_LOADING_TICKET)
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="text-muted">
|
||||
{{ trans(CHILL_TICKET_LIST_LOADING_TICKET) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ticket list -->
|
||||
<ticket-list-component
|
||||
v-else
|
||||
:tickets="ticketList"
|
||||
title=""
|
||||
:hasMoreTickets="pagination.next !== null"
|
||||
@fetchNextPage="fetchNextPage"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
// Components
|
||||
import TicketListComponent from "../../../../../ChillTicketBundle/src/Resources/public/vuejs/TicketList/components/TicketListComponent.vue";
|
||||
|
||||
// Types
|
||||
import { Pagination } from "ChillMainAssets/lib/api/apiMethods";
|
||||
import { TicketSimple } from "src/Bundle/ChillTicketBundle/src/Resources/public/types";
|
||||
|
||||
// Translation
|
||||
import { CHILL_TICKET_LIST_LOADING_TICKET, trans } from "translator";
|
||||
|
||||
const store = useStore();
|
||||
const pagination = computed(() => store.getters.getPagination as Pagination);
|
||||
|
||||
const ticketList = computed(
|
||||
() => store.getters.getTicketList as TicketSimple[],
|
||||
);
|
||||
const isTicketLoading = computed(() => store.getters.isTicketLoading);
|
||||
|
||||
const fetchNextPage = async () => {
|
||||
if (pagination.value.next) {
|
||||
await store.dispatch("fetchTicketListByUrl", pagination.value.next);
|
||||
}
|
||||
};
|
||||
</script>
|
@@ -1,26 +1,27 @@
|
||||
<template>
|
||||
<div class="alert alert-light">
|
||||
{{ $t("my_workflows.description") }}
|
||||
{{ trans(MY_WORKFLOWS_DESCRIPTION) }}
|
||||
</div>
|
||||
<my-workflows-table :workflows="workflows" />
|
||||
|
||||
<div class="alert alert-light">
|
||||
{{ $t("my_workflows.description_cc") }}
|
||||
{{ trans(MY_WORKFLOWS_DESCRIPTION_CC) }}
|
||||
</div>
|
||||
<my-workflows-table :workflows="workflowsCc" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from "vuex";
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import MyWorkflowsTable from "./MyWorkflowsTable.vue";
|
||||
import {
|
||||
MY_WORKFLOWS_DESCRIPTION,
|
||||
MY_WORKFLOWS_DESCRIPTION_CC,
|
||||
trans,
|
||||
} from "translator";
|
||||
|
||||
export default {
|
||||
name: "MyWorkflows",
|
||||
components: {
|
||||
MyWorkflowsTable,
|
||||
},
|
||||
computed: {
|
||||
...mapState(["workflows", "workflowsCc"]),
|
||||
},
|
||||
};
|
||||
const store = useStore();
|
||||
|
||||
const workflows = computed(() => store.state.homepage.workflows);
|
||||
const workflowsCc = computed(() => store.state.homepage.workflowsCc);
|
||||
</script>
|
||||
|
@@ -1,17 +1,17 @@
|
||||
<template>
|
||||
<span v-if="hasNoResults(workflows)" class="chill-no-data-statement">{{
|
||||
$t("no_data")
|
||||
}}</span>
|
||||
<span v-if="hasNoResults" class="chill-no-data-statement">
|
||||
{{ trans(NO_DATA) }}
|
||||
</span>
|
||||
<tab-table v-else>
|
||||
<template #thead>
|
||||
<th scope="col">
|
||||
{{ $t("Object_workflow") }}
|
||||
{{ trans(OBJECT_WORKFLOW) }}
|
||||
</th>
|
||||
<th scope="col">
|
||||
{{ $t("Step") }}
|
||||
{{ trans(STEP) }}
|
||||
</th>
|
||||
<th scope="col">
|
||||
{{ $t("concerned_users") }}
|
||||
{{ trans(CONCERNED_USERS) }}
|
||||
</th>
|
||||
<th scope="col" />
|
||||
</template>
|
||||
@@ -29,7 +29,7 @@
|
||||
<span
|
||||
v-if="w.isOnHoldAtCurrentStep"
|
||||
class="badge bg-success rounded-pill"
|
||||
>{{ $t("on_hold") }}</span
|
||||
>{{ trans(ON_HOLD) }}</span
|
||||
>
|
||||
</div>
|
||||
</td>
|
||||
@@ -46,7 +46,7 @@
|
||||
</td>
|
||||
<td>
|
||||
<a class="btn btn-sm btn-show" :href="getUrl(w)">
|
||||
{{ $t("show_entity", { entity: $t("the_workflow") }) }}
|
||||
{{ trans(SHOW_ENTITY, { entity: trans(THE_WORKFLOW) }) }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -54,38 +54,48 @@
|
||||
</tab-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from "vuex";
|
||||
import TabTable from "./TabTable";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly";
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import TabTable from "./TabTable.vue";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
||||
import { Workflow } from "ChillPersonAssets/types";
|
||||
import {
|
||||
CONCERNED_USERS,
|
||||
OBJECT_WORKFLOW,
|
||||
ON_HOLD,
|
||||
SHOW_ENTITY,
|
||||
THE_WORKFLOW,
|
||||
NO_DATA,
|
||||
STEP,
|
||||
trans,
|
||||
} from "translator";
|
||||
import { PaginationResponse } from "ChillMainAssets/lib/api/apiMethods";
|
||||
|
||||
export default {
|
||||
name: "MyWorkflows",
|
||||
components: {
|
||||
TabTable,
|
||||
OnTheFly,
|
||||
},
|
||||
props: ["workflows"],
|
||||
computed: {
|
||||
...mapGetters(["isWorkflowsLoaded"]),
|
||||
},
|
||||
methods: {
|
||||
hasNoResults(workflows) {
|
||||
if (!this.isWorkflowsLoaded) {
|
||||
return false;
|
||||
} else {
|
||||
return workflows.count === 0;
|
||||
}
|
||||
},
|
||||
getUrl(w) {
|
||||
return `/fr/main/workflow/${w.id}/show`;
|
||||
},
|
||||
getStep(w) {
|
||||
const lastStep = w.steps.length - 1;
|
||||
return w.steps[lastStep].currentStep.text;
|
||||
},
|
||||
},
|
||||
};
|
||||
const props = defineProps<{
|
||||
workflows: PaginationResponse<Workflow>;
|
||||
}>();
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const isWorkflowsLoaded = computed(() => store.getters.isWorkflowsLoaded);
|
||||
|
||||
const hasNoResults = computed(() => {
|
||||
if (!isWorkflowsLoaded.value) {
|
||||
return false;
|
||||
} else {
|
||||
return props.workflows.count === 0;
|
||||
}
|
||||
});
|
||||
|
||||
function getUrl(w: Workflow): string {
|
||||
return `/fr/main/workflow/${w.id}/show`;
|
||||
}
|
||||
|
||||
function getStep(w: Workflow): string {
|
||||
const lastStep = w.steps.length - 1;
|
||||
return w.steps[lastStep].currentStep.text;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@@ -1,27 +1,26 @@
|
||||
// CURRENTLY NOT IN USE
|
||||
<template>
|
||||
<div class="accompanying-course-work">
|
||||
<div class="alert alert-light">
|
||||
{{ $t("my_works.description") }}
|
||||
{{ trans(MY_WORKS_DESCRIPTION) }}
|
||||
</div>
|
||||
<span v-if="noResults" class="chill-no-data-statement">{{
|
||||
$t("no_data")
|
||||
}}</span>
|
||||
<span v-if="noResults" class="chill-no-data-statement">
|
||||
{{ trans(NO_DATA) }}
|
||||
</span>
|
||||
<tab-table v-else>
|
||||
<template #thead>
|
||||
<th scope="col">
|
||||
{{ $t("StartDate") }}
|
||||
{{ trans(START_DATE) }}
|
||||
</th>
|
||||
<th scope="col">
|
||||
{{ $t("SocialAction") }}
|
||||
{{ trans(SOCIAL_ACTION) }}
|
||||
</th>
|
||||
<th scope="col">
|
||||
{{ $t("concerned_persons") }}
|
||||
{{ trans(CONCERNED_PERSONS) }}
|
||||
</th>
|
||||
<th scope="col" />
|
||||
</template>
|
||||
<template #tbody>
|
||||
<tr v-for="(w, i) in works.results" :key="`works-${i}`">
|
||||
<tr v-for="(w, i) in works.value.results" :key="`works-${i}`">
|
||||
<td>{{ $d(w.startDate.datetime, "short") }}</td>
|
||||
<td>
|
||||
<span class="chill-entity entity-social-issue">
|
||||
@@ -51,8 +50,8 @@
|
||||
<div class="btn-group-vertical" role="group" aria-label="Actions">
|
||||
<a class="btn btn-sm btn-update" :href="getUrl(w)">
|
||||
{{
|
||||
$t("show_entity", {
|
||||
entity: $t("the_action"),
|
||||
trans(SHOW_ENTITY, {
|
||||
entity: trans(THE_ACTION),
|
||||
})
|
||||
}}
|
||||
</a>
|
||||
@@ -61,8 +60,8 @@
|
||||
:href="getUrl(w.accompanyingPeriod)"
|
||||
>
|
||||
{{
|
||||
$t("show_entity", {
|
||||
entity: $t("the_course"),
|
||||
trans(SHOW_ENTITY, {
|
||||
entity: trans(THE_COURSE),
|
||||
})
|
||||
}}
|
||||
</a>
|
||||
@@ -74,41 +73,47 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapGetters } from "vuex";
|
||||
import TabTable from "./TabTable";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly";
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import TabTable from "./TabTable.vue";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
||||
import {
|
||||
MY_WORKS_DESCRIPTION,
|
||||
CONCERNED_PERSONS,
|
||||
SHOW_ENTITY,
|
||||
THE_COURSE,
|
||||
THE_ACTION,
|
||||
SOCIAL_ACTION,
|
||||
START_DATE,
|
||||
NO_DATA,
|
||||
trans,
|
||||
} from "translator";
|
||||
import { Workflow } from "ChillPersonAssets/types";
|
||||
|
||||
export default {
|
||||
name: "MyWorks",
|
||||
components: {
|
||||
TabTable,
|
||||
OnTheFly,
|
||||
},
|
||||
computed: {
|
||||
...mapState(["works"]),
|
||||
...mapGetters(["isWorksLoaded"]),
|
||||
noResults() {
|
||||
if (!this.isWorksLoaded) {
|
||||
return false;
|
||||
} else {
|
||||
return this.works.count === 0;
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getUrl(e) {
|
||||
switch (e.type) {
|
||||
case "accompanying_period_work":
|
||||
return `/fr/person/accompanying-period/work/${e.id}/edit`;
|
||||
case "accompanying_period":
|
||||
return `/fr/parcours/${e.id}`;
|
||||
default:
|
||||
throw "entity type unknown";
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
const store = useStore();
|
||||
|
||||
const works = computed(() => store.state.homepage.works);
|
||||
const isWorksLoaded = computed(() => store.getters.isWorksLoaded);
|
||||
|
||||
const noResults = computed(() => {
|
||||
if (!isWorksLoaded.value) {
|
||||
return false;
|
||||
} else {
|
||||
return works.value.count === 0;
|
||||
}
|
||||
});
|
||||
|
||||
function getUrl(e: Workflow): string {
|
||||
switch (e.type) {
|
||||
case "accompanying_period_work":
|
||||
return `/fr/person/accompanying-period/work/${e.id}/edit`;
|
||||
case "accompanying_period":
|
||||
return `/fr/parcours/${e.id}`;
|
||||
default:
|
||||
throw "entity type unknown";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
@@ -4,14 +4,14 @@
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "TabCounter",
|
||||
props: ["count"],
|
||||
computed: {
|
||||
isCounterAvailable() {
|
||||
return typeof this.count !== "undefined" && this.count > 0;
|
||||
},
|
||||
},
|
||||
};
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
count: number;
|
||||
}>();
|
||||
|
||||
const isCounterAvailable = computed(
|
||||
() => typeof props.count !== "undefined" && props.count > 0,
|
||||
);
|
||||
</script>
|
||||
|
@@ -11,11 +11,8 @@
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "TabTable",
|
||||
props: [],
|
||||
};
|
||||
<script lang="ts" setup>
|
||||
// Pas de props à définir, composant slot simple
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
@@ -1,89 +0,0 @@
|
||||
const appMessages = {
|
||||
fr: {
|
||||
main_title: "Vue d'ensemble",
|
||||
my_works: {
|
||||
tab: "Mes actions",
|
||||
description:
|
||||
"Liste des actions d'accompagnement dont je suis référent et qui arrivent à échéance.",
|
||||
},
|
||||
my_evaluations: {
|
||||
tab: "Mes évaluations",
|
||||
description:
|
||||
"Liste des évaluations dont je suis référent et qui arrivent à échéance.",
|
||||
},
|
||||
my_tasks: {
|
||||
tab: "Mes tâches",
|
||||
description_alert:
|
||||
"Liste des tâches auxquelles je suis assigné et dont la date de rappel est dépassée.",
|
||||
description_warning:
|
||||
"Liste des tâches auxquelles je suis assigné et dont la date d'échéance est dépassée.",
|
||||
},
|
||||
my_accompanying_courses: {
|
||||
tab: "Mes nouveaux parcours",
|
||||
description:
|
||||
"Liste des parcours d'accompagnement que l'on vient de m'attribuer depuis moins de 15 jours.",
|
||||
},
|
||||
my_notifications: {
|
||||
tab: "Mes nouvelles notifications",
|
||||
description: "Liste des notifications reçues et non lues.",
|
||||
},
|
||||
my_workflows: {
|
||||
tab: "Mes workflows",
|
||||
description: "Liste des workflows en attente d'une action.",
|
||||
description_cc: "Liste des workflows dont je suis en copie.",
|
||||
},
|
||||
opening_date: "Date d'ouverture",
|
||||
social_issues: "Problématiques sociales",
|
||||
concerned_persons: "Usagers concernés",
|
||||
max_date: "Date d'échéance",
|
||||
warning_date: "Date de rappel",
|
||||
evaluation: "Évaluation",
|
||||
task: "Tâche",
|
||||
Date: "Date",
|
||||
From: "Expéditeur",
|
||||
Subject: "Objet",
|
||||
Entity: "Associé à",
|
||||
Step: "Étape",
|
||||
concerned_users: "Usagers concernés",
|
||||
Object_workflow: "Objet du workflow",
|
||||
on_hold: "En attente",
|
||||
show_entity: "Voir {entity}",
|
||||
the_activity: "l'échange",
|
||||
the_course: "le parcours",
|
||||
the_action: "l'action",
|
||||
the_evaluation: "l'évaluation",
|
||||
the_evaluation_document: "le document",
|
||||
the_task: "la tâche",
|
||||
the_workflow: "le workflow",
|
||||
StartDate: "Date d'ouverture",
|
||||
SocialAction: "Action d'accompagnement",
|
||||
no_data: "Aucun résultats",
|
||||
no_dashboard: "Pas de tableaux de bord",
|
||||
counter: {
|
||||
unread_notifications:
|
||||
"{n} notification non lue | {n} notifications non lues",
|
||||
assignated_courses:
|
||||
"{n} parcours récent assigné | {n} parcours récents assignés",
|
||||
assignated_actions: "{n} action assignée | {n} actions assignées",
|
||||
assignated_evaluations:
|
||||
"{n} évaluation assignée | {n} évaluations assignées",
|
||||
alert_tasks: "{n} tâche en rappel | {n} tâches en rappel",
|
||||
warning_tasks: "{n} tâche à échéance | {n} tâches à échéance",
|
||||
},
|
||||
emergency: "Urgent",
|
||||
confidential: "Confidentiel",
|
||||
automatic_notification: "Notification automatique",
|
||||
widget: {
|
||||
news: {
|
||||
title: "Actualités",
|
||||
readMore: "Lire la suite",
|
||||
date: "Date",
|
||||
none: "Aucune actualité",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
Object.assign(appMessages.fr);
|
||||
|
||||
export { appMessages };
|
@@ -0,0 +1,55 @@
|
||||
import { createStore } from "vuex";
|
||||
import { State as HomepageStates, moduleHomepage } from "./modules/homepage";
|
||||
|
||||
import {
|
||||
State as TicketListStates,
|
||||
moduleTicketList,
|
||||
} from "../../../../../../ChillTicketBundle/src/Resources/public/vuejs/TicketApp/store/modules/ticket_list";
|
||||
import {
|
||||
State as TicketStates,
|
||||
moduleTicket,
|
||||
} from "../../../../../../ChillTicketBundle/src/Resources/public/vuejs/TicketApp/store/modules/ticket";
|
||||
import {
|
||||
State as CommentStates,
|
||||
moduleComment,
|
||||
} from "../../../../../../ChillTicketBundle/src/Resources/public/vuejs/TicketApp/store/modules/comment";
|
||||
import {
|
||||
moduleMotive,
|
||||
State as MotiveStates,
|
||||
} from "../../../../../../ChillTicketBundle/src/Resources/public/vuejs/TicketApp/store/modules/motive";
|
||||
import {
|
||||
State as AddresseeStates,
|
||||
moduleAddressee,
|
||||
} from "../../../../../../ChillTicketBundle/src/Resources/public/vuejs/TicketApp/store/modules/addressee";
|
||||
import {
|
||||
modulePersons,
|
||||
State as PersonsState,
|
||||
} from "../../../../../../ChillTicketBundle/src/Resources/public/vuejs/TicketApp/store/modules/persons";
|
||||
|
||||
import {
|
||||
moduleUser,
|
||||
State as UserState,
|
||||
} from "../../../../../../ChillTicketBundle/src/Resources/public/vuejs/TicketApp/store/modules/user";
|
||||
|
||||
export interface RootState {
|
||||
homepage: HomepageStates;
|
||||
motive: MotiveStates;
|
||||
ticket: TicketStates;
|
||||
comment: CommentStates;
|
||||
addressee: AddresseeStates;
|
||||
persons: PersonsState;
|
||||
ticketList: TicketListStates;
|
||||
user: UserState;
|
||||
}
|
||||
export const store = createStore<RootState>({
|
||||
modules: {
|
||||
homepage: moduleHomepage,
|
||||
motive: moduleMotive,
|
||||
ticket: moduleTicket,
|
||||
comment: moduleComment,
|
||||
addressee: moduleAddressee,
|
||||
person: modulePersons,
|
||||
ticketList: moduleTicketList,
|
||||
user: moduleUser,
|
||||
},
|
||||
});
|
@@ -1,90 +1,113 @@
|
||||
import "es6-promise/auto";
|
||||
import { createStore } from "vuex";
|
||||
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
|
||||
import { Module } from "vuex";
|
||||
import {
|
||||
makeFetch,
|
||||
PaginationResponse,
|
||||
} from "ChillMainAssets/lib/api/apiMethods";
|
||||
import {
|
||||
AccompanyingCourse,
|
||||
Alert,
|
||||
Evaluation,
|
||||
Warning,
|
||||
Workflow,
|
||||
WorflowCc,
|
||||
} from "ChillPersonAssets/types";
|
||||
import { RootState } from "..";
|
||||
|
||||
const debug = process.env.NODE_ENV !== "production";
|
||||
export interface TasksState {
|
||||
warning: PaginationResponse<Warning>;
|
||||
alert: PaginationResponse<Alert>;
|
||||
}
|
||||
|
||||
const isEmpty = (obj) => {
|
||||
return (
|
||||
obj &&
|
||||
Object.keys(obj).length <= 1 &&
|
||||
Object.getPrototypeOf(obj) === Object.prototype
|
||||
);
|
||||
};
|
||||
export interface State {
|
||||
evaluations: PaginationResponse<Evaluation>;
|
||||
tasks: TasksState;
|
||||
accompanyingCourses: PaginationResponse<AccompanyingCourse>;
|
||||
notifications: PaginationResponse<Notification>;
|
||||
workflows: PaginationResponse<Workflow>;
|
||||
workflowsCc: PaginationResponse<WorflowCc>;
|
||||
errorMsg: unknown[];
|
||||
loading: boolean;
|
||||
ticketsLoading: boolean;
|
||||
}
|
||||
|
||||
const store = createStore({
|
||||
strict: debug,
|
||||
export const moduleHomepage: Module<State, RootState> = {
|
||||
state: {
|
||||
// works: {},
|
||||
evaluations: {},
|
||||
evaluations: {
|
||||
count: 0,
|
||||
} as PaginationResponse<Evaluation>,
|
||||
tasks: {
|
||||
warning: {},
|
||||
alert: {},
|
||||
warning: {
|
||||
count: 0,
|
||||
} as PaginationResponse<Warning>,
|
||||
alert: {
|
||||
count: 0,
|
||||
} as PaginationResponse<Alert>,
|
||||
},
|
||||
accompanyingCourses: {},
|
||||
notifications: {},
|
||||
workflows: {},
|
||||
workflowsCc: {},
|
||||
accompanyingCourses: {
|
||||
count: 0,
|
||||
} as PaginationResponse<AccompanyingCourse>,
|
||||
notifications: {
|
||||
count: 0,
|
||||
} as PaginationResponse<Notification>,
|
||||
workflows: {
|
||||
count: 0,
|
||||
} as PaginationResponse<Workflow>,
|
||||
workflowsCc: {
|
||||
count: 0,
|
||||
} as PaginationResponse<WorflowCc>,
|
||||
ticketsLoading: false,
|
||||
errorMsg: [],
|
||||
loading: false,
|
||||
},
|
||||
getters: {
|
||||
// isWorksLoaded(state) {
|
||||
// return !isEmpty(state.works);
|
||||
// },
|
||||
isTicketLoading: (state) => {
|
||||
return state.ticketsLoading;
|
||||
},
|
||||
isEvaluationsLoaded(state) {
|
||||
return !isEmpty(state.evaluations);
|
||||
return Array.isArray(state.evaluations.results);
|
||||
},
|
||||
isTasksWarningLoaded(state) {
|
||||
return !isEmpty(state.tasks.warning);
|
||||
return Array.isArray(state.tasks.warning.results);
|
||||
},
|
||||
isTasksAlertLoaded(state) {
|
||||
return !isEmpty(state.tasks.alert);
|
||||
return Array.isArray(state.tasks.alert.results);
|
||||
},
|
||||
isAccompanyingCoursesLoaded(state) {
|
||||
return !isEmpty(state.accompanyingCourses);
|
||||
return Array.isArray(state.accompanyingCourses.results);
|
||||
},
|
||||
isNotificationsLoaded(state) {
|
||||
return !isEmpty(state.notifications);
|
||||
return Array.isArray(state.notifications.results);
|
||||
},
|
||||
isWorkflowsLoaded(state) {
|
||||
return !isEmpty(state.workflows);
|
||||
return Array.isArray(state.workflows.results);
|
||||
},
|
||||
counter(state) {
|
||||
counter(state, getters, rootState, rootGetters) {
|
||||
return {
|
||||
// works: state.works.count,
|
||||
evaluations: state.evaluations.count,
|
||||
tasksWarning: state.tasks.warning.count,
|
||||
tasksAlert: state.tasks.alert.count,
|
||||
accompanyingCourses: state.accompanyingCourses.count,
|
||||
notifications: state.notifications.count,
|
||||
workflows: state.workflows.count,
|
||||
tickets: rootGetters["ticketList/getCount"] || 0,
|
||||
evaluations: state.evaluations.count || 0,
|
||||
tasksWarning: state.tasks.warning.count || 0,
|
||||
tasksAlert: state.tasks.alert.count || 0,
|
||||
accompanyingCourses: state.accompanyingCourses.count || 0,
|
||||
notifications: state.notifications.count || 0,
|
||||
workflows: state.workflows.count || 0,
|
||||
};
|
||||
},
|
||||
},
|
||||
mutations: {
|
||||
// addWorks(state, works) {
|
||||
// //console.log('addWorks', works);
|
||||
// state.works = works;
|
||||
// },
|
||||
addEvaluations(state, evaluations) {
|
||||
//console.log('addEvaluations', evaluations);
|
||||
state.evaluations = evaluations;
|
||||
},
|
||||
addTasksWarning(state, tasks) {
|
||||
//console.log('addTasksWarning', tasks);
|
||||
state.tasks.warning = tasks;
|
||||
},
|
||||
addTasksAlert(state, tasks) {
|
||||
//console.log('addTasksAlert', tasks);
|
||||
state.tasks.alert = tasks;
|
||||
},
|
||||
addCourses(state, courses) {
|
||||
//console.log('addCourses', courses);
|
||||
state.accompanyingCourses = courses;
|
||||
},
|
||||
addNotifications(state, notifications) {
|
||||
//console.log('addNotifications', notifications);
|
||||
state.notifications = notifications;
|
||||
},
|
||||
addWorkflows(state, workflows) {
|
||||
@@ -96,29 +119,29 @@ const store = createStore({
|
||||
setLoading(state, bool) {
|
||||
state.loading = bool;
|
||||
},
|
||||
setTicketsLoading(state, bool) {
|
||||
state.ticketsLoading = bool;
|
||||
},
|
||||
catchError(state, error) {
|
||||
state.errorMsg.push(error);
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
getByTab({ commit, getters }, { tab, param }) {
|
||||
async getByTab({ commit, getters, dispatch }, { tab, param }) {
|
||||
switch (tab) {
|
||||
// case 'MyWorks':
|
||||
// if (!getters.isWorksLoaded) {
|
||||
// commit('setLoading', true);
|
||||
// const url = `/api/1.0/person/accompanying-period/work/my-near-end${'?'+ param}`;
|
||||
// makeFetch('GET', url)
|
||||
// .then((response) => {
|
||||
// commit('addWorks', response);
|
||||
// commit('setLoading', false);
|
||||
// })
|
||||
// .catch((error) => {
|
||||
// commit('catchError', error);
|
||||
// throw error;
|
||||
// })
|
||||
// ;
|
||||
// }
|
||||
// break;
|
||||
case "MyTickets":
|
||||
if (!getters.isTicketsLoaded) {
|
||||
commit("setTicketsLoading", true);
|
||||
// Utilise l'action du module ticket_list
|
||||
await dispatch(
|
||||
"fetchTicketList",
|
||||
{ byAddresseeToMe: true },
|
||||
{ root: true },
|
||||
);
|
||||
|
||||
commit("setTicketsLoading", false);
|
||||
}
|
||||
break;
|
||||
case "MyEvaluations":
|
||||
if (!getters.isEvaluationsLoaded) {
|
||||
commit("setLoading", true);
|
||||
@@ -180,7 +203,6 @@ const store = createStore({
|
||||
const url = `/api/1.0/main/notification/my/unread${"?" + param}`;
|
||||
makeFetch("GET", url)
|
||||
.then((response) => {
|
||||
console.log("notifications", response);
|
||||
commit("addNotifications", response);
|
||||
commit("setLoading", false);
|
||||
})
|
||||
@@ -217,6 +239,4 @@ const store = createStore({
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export { store };
|
||||
};
|
@@ -46,10 +46,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul
|
||||
class="badge-suggest add-items inline"
|
||||
style="justify-content: flex-end; display: flex"
|
||||
>
|
||||
<ul class="badge-suggest add-items inline text-end">
|
||||
<li
|
||||
v-for="s in suggested"
|
||||
:key="s.type + s.id"
|
||||
|
@@ -44,16 +44,16 @@ class SearchUserGroupApiProvider implements SearchApiInterface, LocaleAwareInter
|
||||
|
||||
public function provideQuery(string $pattern, array $parameters): SearchApiQuery
|
||||
{
|
||||
return $this->userGroupRepository->provideSearchApiQuery($pattern, $this->getLocale(), 'user-group');
|
||||
return $this->userGroupRepository->provideSearchApiQuery($pattern, $this->getLocale(), 'user_group');
|
||||
}
|
||||
|
||||
public function supportsResult(string $key, array $metadatas): bool
|
||||
{
|
||||
return 'user-group' === $key;
|
||||
return 'user_group' === $key;
|
||||
}
|
||||
|
||||
public function supportsTypes(string $pattern, array $types, array $parameters): bool
|
||||
{
|
||||
return in_array('user-group', $types, true);
|
||||
return in_array('user_group', $types, true);
|
||||
}
|
||||
}
|
||||
|
@@ -305,7 +305,7 @@ paths:
|
||||
- thirdparty
|
||||
- user
|
||||
- household
|
||||
- user-group
|
||||
- user_group
|
||||
responses:
|
||||
200:
|
||||
description: "OK"
|
||||
|
@@ -26,7 +26,7 @@ module.exports = function (encore, entries) {
|
||||
);
|
||||
encore.addEntry(
|
||||
"page_homepage_widget",
|
||||
__dirname + "/Resources/public/page/homepage_widget/index.js",
|
||||
__dirname + "/Resources/public/page/homepage_widget/index.ts",
|
||||
);
|
||||
encore.addEntry(
|
||||
"page_export",
|
||||
|
@@ -191,3 +191,61 @@ pick_entity:
|
||||
one {Tiers}
|
||||
other {Tiers}
|
||||
}
|
||||
|
||||
loading: "Chargement..."
|
||||
main_title: "Vue d'ensemble"
|
||||
my_tickets.tab: "Mes Tickets"
|
||||
my_works.tab: "Mes actions"
|
||||
my_works.description: "Liste des actions d'accompagnement dont je suis référent et qui arrivent à échéance."
|
||||
my_evaluations.tab: "Mes évaluations"
|
||||
my_evaluations.description: "Liste des évaluations dont je suis référent et qui arrivent à échéance."
|
||||
my_tasks.tab: "Mes tâches"
|
||||
my_tasks.description_alert: "Liste des tâches auxquelles je suis assigné et dont la date de rappel est dépassée."
|
||||
my_tasks.description_warning: "Liste des tâches auxquelles je suis assigné et dont la date d'échéance est dépassée."
|
||||
my_accompanying_courses.tab: "Mes nouveaux parcours"
|
||||
my_accompanying_courses.description: "Liste des parcours d'accompagnement que l'on vient de m'attribuer depuis moins de 15 jours."
|
||||
my_notifications.tab: "Mes nouvelles notifications"
|
||||
my_notifications.description: "Liste des notifications reçues et non lues."
|
||||
my_workflows.tab: "Mes workflows"
|
||||
my_workflows.description: "Liste des workflows en attente d'une action."
|
||||
my_workflows.description_cc: "Liste des workflows dont je suis en copie."
|
||||
opening_date: "Date d'ouverture"
|
||||
social_issues: "Problématiques sociales"
|
||||
concerned_persons: "Usagers concernés"
|
||||
max_date: "Date d'échéance"
|
||||
warning_date: "Date de rappel"
|
||||
evaluation: "Évaluation"
|
||||
task: "Tâche"
|
||||
Date: "Date"
|
||||
From: "Expéditeur"
|
||||
Subject: "Objet"
|
||||
Entity: "Associé à"
|
||||
Step: "Étape"
|
||||
concerned_users: "Usagers concernés"
|
||||
Object_workflow: "Objet du workflow"
|
||||
on_hold: "En attente"
|
||||
show_entity: "Voir {entity}"
|
||||
the_activity: "l'échange"
|
||||
the_course: "le parcours"
|
||||
the_action: "l'action"
|
||||
the_evaluation: "l'évaluation"
|
||||
the_evaluation_document: "le document"
|
||||
the_task: "la tâche"
|
||||
the_workflow: "le workflow"
|
||||
StartDate: "Date d'ouverture"
|
||||
SocialAction: "Action d'accompagnement"
|
||||
no_data: "Aucun résultats"
|
||||
no_dashboard: "Pas de tableaux de bord"
|
||||
counter.unread_notifications: "{n, plural, one {# notification non lue} other {# notifications non lues}}"
|
||||
counter.assignated_courses: "{n, plural, one {# parcours récent assigné} other {# parcours récents assignés}}"
|
||||
counter.assignated_actions: "{n, plural, one {# action assignée} other {# actions assignées}}"
|
||||
counter.assignated_evaluations: "{n, plural, one {# évaluation assignée} other {# évaluations assignées}}"
|
||||
counter.alert_tasks: "{n, plural, one {# tâche en rappel} other {# tâches en rappel}}"
|
||||
counter.warning_tasks: "{n, plural, one {# tâche à échéance} other {# tâches à échéance}}"
|
||||
emergency: "Urgent"
|
||||
confidential: "Confidentiel"
|
||||
automatic_notification: "Notification automatique"
|
||||
widget.news.title: "Actualités"
|
||||
widget.news.readMore: "Lire la suite"
|
||||
widget.news.date: "Date"
|
||||
widget.news.none: "Aucune actualité"
|
||||
|
@@ -14,12 +14,12 @@ import {
|
||||
import { StoredObject } from "ChillDocStoreAssets/types";
|
||||
import { Thirdparty } from "../../../ChillThirdPartyBundle/Resources/public/types";
|
||||
import { Calendar } from "../../../ChillCalendarBundle/Resources/public/types";
|
||||
import Person from "./vuejs/_components/OnTheFly/Person.vue";
|
||||
|
||||
export interface AltName {
|
||||
label: string;
|
||||
key: string;
|
||||
}
|
||||
|
||||
export interface Person {
|
||||
id: number;
|
||||
type: "person";
|
||||
@@ -45,6 +45,7 @@ export interface Person {
|
||||
|
||||
export interface AccompanyingPeriod {
|
||||
id: number;
|
||||
type: "accompanying_period";
|
||||
addressLocation?: Address | null;
|
||||
administrativeLocation?: Location | null;
|
||||
calendars: Calendar[];
|
||||
@@ -81,6 +82,7 @@ export interface AccompanyingPeriod {
|
||||
|
||||
export interface AccompanyingPeriodWork {
|
||||
id: number;
|
||||
type: "accompanying_period_work";
|
||||
accompanyingPeriod?: AccompanyingPeriod;
|
||||
accompanyingPeriodWorkEvaluations: AccompanyingPeriodWorkEvaluation[];
|
||||
createdAt?: string;
|
||||
@@ -105,6 +107,7 @@ export interface AccompanyingPeriodWork {
|
||||
|
||||
export interface SocialAction {
|
||||
id: number;
|
||||
text: string;
|
||||
parent?: SocialAction | null;
|
||||
children: SocialAction[];
|
||||
issue?: SocialIssue | null;
|
||||
@@ -166,6 +169,7 @@ export interface AccompanyingPeriodLocationHistory {
|
||||
|
||||
export interface SocialIssue {
|
||||
id: number;
|
||||
text: string;
|
||||
parent?: SocialIssue | null;
|
||||
children: SocialIssue[];
|
||||
socialActions?: SocialAction[] | null;
|
||||
@@ -206,6 +210,7 @@ export interface AccompanyingPeriodWorkGoal {
|
||||
}
|
||||
|
||||
export interface AccompanyingPeriodWorkEvaluation {
|
||||
type: "accompanying_period_work_evaluation";
|
||||
accompanyingPeriodWork: AccompanyingPeriodWork | null;
|
||||
comment: string;
|
||||
createdAt: DateTime | null;
|
||||
@@ -236,6 +241,68 @@ export interface Evaluation {
|
||||
notificationDelay: string;
|
||||
}
|
||||
|
||||
export interface Step {
|
||||
currentStep: {
|
||||
text: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Workflow {
|
||||
id: number;
|
||||
title: string;
|
||||
type: "accompanying_period_work" | "accompanying_period";
|
||||
isOnHoldAtCurrentStep: boolean;
|
||||
datas: {
|
||||
persons: Person[];
|
||||
};
|
||||
steps: Step[];
|
||||
}
|
||||
|
||||
export interface WorflowCc {
|
||||
id: number;
|
||||
title: string;
|
||||
isOnHoldAtCurrentStep: boolean;
|
||||
datas: {
|
||||
persons: Person[];
|
||||
};
|
||||
steps: Step[];
|
||||
}
|
||||
|
||||
export interface Warning {
|
||||
id: number;
|
||||
warningDate: DateTime;
|
||||
endDate: DateTime;
|
||||
title: string;
|
||||
}
|
||||
export interface Alert {
|
||||
id: number;
|
||||
warningDate: DateTime;
|
||||
endDate: DateTime;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface Notification {
|
||||
id: number;
|
||||
date: DateTime;
|
||||
title: string;
|
||||
sender: {
|
||||
text: string;
|
||||
};
|
||||
relatedEntityClass: string;
|
||||
relatedEntityId: number;
|
||||
}
|
||||
export interface Participation {
|
||||
person: Person;
|
||||
}
|
||||
export interface AccompanyingCourse {
|
||||
id: number;
|
||||
openingDate: DateTime;
|
||||
socialIssues: SocialIssue[];
|
||||
participations: Participation[];
|
||||
emergency: boolean;
|
||||
confidential: boolean;
|
||||
}
|
||||
|
||||
export interface AccompanyingPeriodWorkReferrerHistory {
|
||||
id: number;
|
||||
accompanyingPeriodWork: AccompanyingPeriodWork;
|
||||
|
@@ -165,6 +165,7 @@ export interface TicketFilters {
|
||||
byCreatedBefore: string;
|
||||
byResponseTimeExceeded: boolean;
|
||||
byAddresseeToMe: boolean;
|
||||
byTicketId: number | null;
|
||||
}
|
||||
|
||||
export interface TicketFilterParams {
|
||||
@@ -179,6 +180,7 @@ export interface TicketFilterParams {
|
||||
byCreatedBefore?: string;
|
||||
byResponseTimeExceeded?: string;
|
||||
byAddresseeToMe?: boolean;
|
||||
byTicketId?: number;
|
||||
}
|
||||
|
||||
export interface TicketInitForm {
|
||||
|
@@ -1,20 +1,11 @@
|
||||
<template>
|
||||
<div class="col-12">
|
||||
<div class="col-12" v-if="!commentHistory.deleted">
|
||||
<blockquote class="chill-user-quote">
|
||||
<button
|
||||
class="btn btn-sm btn-primary float-end"
|
||||
title="Visible"
|
||||
@click="visibleComment"
|
||||
v-if="commentHistory.deleted"
|
||||
>
|
||||
<i class="bi bi-eye"></i>
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-sm bg-chill-red float-end text-white"
|
||||
@click="maskComment"
|
||||
v-else
|
||||
@click="deleteComment"
|
||||
>
|
||||
<i class="bi bi-eye-slash"></i>
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-sm btn-edit mx-2 float-end text-white"
|
||||
@@ -24,14 +15,16 @@
|
||||
/>
|
||||
|
||||
<p v-html="convertMarkdownToHtml(commentHistory.content)"></p>
|
||||
<span
|
||||
v-if="commentHistory.deleted"
|
||||
class="ms-2 d-block text-center fst-italic text-muted"
|
||||
>
|
||||
{{ trans(CHILL_TICKET_TICKET_MASK_COMMENT_HINT) }}
|
||||
</span>
|
||||
</blockquote>
|
||||
</div>
|
||||
<div class="col-12" v-else>
|
||||
<span class="ms-2 d-block text-center">
|
||||
{{ trans(CHILL_TICKET_TICKET_MASK_COMMENT_HINT) }}
|
||||
<button class="btn btn-primary btn-sm ms-2" @click="restoreComment">
|
||||
{{ trans(CANCEL) }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<Modal
|
||||
v-if="editCommentModal"
|
||||
:show="editCommentModal"
|
||||
@@ -75,6 +68,7 @@ import {
|
||||
CHILL_TICKET_TICKET_MASK_COMMENT_SUCCESS,
|
||||
CHILL_TICKET_TICKET_MASK_COMMENT_HINT,
|
||||
CHILL_TICKET_TICKET_VISIBLE_COMMENT_SUCCESS,
|
||||
CANCEL,
|
||||
} from "translator";
|
||||
import { useToast } from "vue-toast-notification";
|
||||
|
||||
@@ -97,18 +91,17 @@ const saveComment = () => {
|
||||
toast.success(trans(CHILL_TICKET_TICKET_EDIT_COMMENT_SUCCESS));
|
||||
};
|
||||
|
||||
const maskComment = () => {
|
||||
store.dispatch("maskComment", props.commentHistory.id);
|
||||
const deleteComment = () => {
|
||||
store.dispatch("deleteComment", props.commentHistory.id);
|
||||
store.commit("addRemovedCommentIds", props.commentHistory.id);
|
||||
editCommentModal.value = false;
|
||||
toast.success(trans(CHILL_TICKET_TICKET_MASK_COMMENT_SUCCESS));
|
||||
};
|
||||
|
||||
const visibleComment = () => {
|
||||
store.dispatch("visibleComment", props.commentHistory.id);
|
||||
const restoreComment = () => {
|
||||
store.dispatch("restoreComment", props.commentHistory.id);
|
||||
editCommentModal.value = false;
|
||||
toast.success(trans(CHILL_TICKET_TICKET_VISIBLE_COMMENT_SUCCESS));
|
||||
};
|
||||
|
||||
const preprocess = (markdown: string): string => {
|
||||
return markdown;
|
||||
};
|
||||
|
@@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<div class="input-group mb-3">
|
||||
<input
|
||||
v-model="ticketId"
|
||||
type="number"
|
||||
class="form-control"
|
||||
:placeholder="trans(CHILL_TICKET_LIST_FILTER_TICKET_ID)"
|
||||
@input="
|
||||
ticketId = isNaN(Number(($event.target as HTMLInputElement).value))
|
||||
? null
|
||||
: Number(($event.target as HTMLInputElement).value)
|
||||
"
|
||||
/>
|
||||
<span class="input-group-text" v-if="ticketId !== null">
|
||||
<i
|
||||
class="fa fa-times chill-red"
|
||||
style="cursor: pointer"
|
||||
@click="ticketId = null"
|
||||
title="clear"
|
||||
></i>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from "vue";
|
||||
// Translation
|
||||
import { trans, CHILL_TICKET_LIST_FILTER_TICKET_ID } from "translator";
|
||||
const props = defineProps<{
|
||||
modelValue: number | null;
|
||||
}>();
|
||||
|
||||
const ticketId = ref<number | null>(props.modelValue);
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newVal) => {
|
||||
if (newVal === null) {
|
||||
ticketId.value = null;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const emit = defineEmits(["update:modelValue"]);
|
||||
|
||||
watch(ticketId, (ticketId) => {
|
||||
emit("update:modelValue", ticketId ? ticketId : null);
|
||||
});
|
||||
</script>
|
@@ -8,23 +8,15 @@ import { ApiException } from "../../../../../../../../ChillMainBundle/Resources/
|
||||
|
||||
export interface State {
|
||||
comments: Comment[];
|
||||
removedCommentIds: Comment["id"][];
|
||||
}
|
||||
|
||||
export const moduleComment: Module<State, RootState> = {
|
||||
state: () => ({
|
||||
comments: [] as Comment[],
|
||||
removedCommentIds: [] as Comment["id"][],
|
||||
}),
|
||||
getters: {
|
||||
canBeDisplayed:
|
||||
(state: State, getters: unknown, rootState: RootState) =>
|
||||
(comment: Comment) => {
|
||||
return (
|
||||
(comment.deleted &&
|
||||
comment.createdBy?.username ===
|
||||
rootState.user.currentUser?.username) ||
|
||||
!comment.deleted
|
||||
);
|
||||
},
|
||||
canBeEdited:
|
||||
(state: State, getters: unknown, rootState: RootState) =>
|
||||
(comment: Comment) => {
|
||||
@@ -32,8 +24,15 @@ export const moduleComment: Module<State, RootState> = {
|
||||
comment.createdBy?.username === rootState.user.currentUser?.username
|
||||
);
|
||||
},
|
||||
getRemovedCommentIds(state) {
|
||||
return state.removedCommentIds;
|
||||
},
|
||||
},
|
||||
mutations: {
|
||||
addRemovedCommentIds(state, commentId: number) {
|
||||
state.removedCommentIds.push(commentId);
|
||||
},
|
||||
},
|
||||
mutations: {},
|
||||
actions: {
|
||||
async createComment({ commit, rootState }, content: Comment["content"]) {
|
||||
try {
|
||||
@@ -64,7 +63,7 @@ export const moduleComment: Module<State, RootState> = {
|
||||
throw error.name;
|
||||
}
|
||||
},
|
||||
async maskComment({ commit }, id: Comment["id"]) {
|
||||
async deleteComment({ commit }, id: Comment["id"]) {
|
||||
try {
|
||||
const result: Comment = await makeFetch(
|
||||
"POST",
|
||||
@@ -77,7 +76,7 @@ export const moduleComment: Module<State, RootState> = {
|
||||
}
|
||||
},
|
||||
|
||||
async visibleComment({ commit }, id: Comment["id"]) {
|
||||
async restoreComment({ commit }, id: Comment["id"]) {
|
||||
try {
|
||||
const result: Comment = await makeFetch(
|
||||
"POST",
|
||||
|
@@ -73,7 +73,10 @@ export const moduleTicketList: Module<State, RootState> = {
|
||||
([, value]) =>
|
||||
value !== undefined &&
|
||||
value !== null &&
|
||||
(value === true || (value !== "" && value.length > 0)),
|
||||
(value === true ||
|
||||
(typeof value === "number" && !isNaN(value)) ||
|
||||
(typeof value === "string" && value !== "") ||
|
||||
(Array.isArray(value) && value.length > 0)),
|
||||
),
|
||||
);
|
||||
params = new URLSearchParams(
|
||||
|
@@ -101,7 +101,6 @@ onMounted(async () => {
|
||||
await store.dispatch("getCurrentUser");
|
||||
await store.dispatch("fetchTicketList", filters);
|
||||
await store.dispatch("fetchMotives");
|
||||
await store.dispatch("fetchUserGroups");
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
@@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<label :for="dateId" class="form-label col-12">
|
||||
{{ label }}
|
||||
</label>
|
||||
<div class="d-flex gap-2">
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="date"
|
||||
:id="dateId"
|
||||
v-model="modelDate"
|
||||
class="form-control"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
<input
|
||||
type="time"
|
||||
v-model="modelTime"
|
||||
class="form-control"
|
||||
:disabled="disabled"
|
||||
style="max-width: 120px"
|
||||
placeholder="hh:mm"
|
||||
/>
|
||||
<span class="input-group-text" v-if="modelDate">
|
||||
<i
|
||||
class="fa fa-times chill-red"
|
||||
style="cursor: pointer"
|
||||
@click="clear"
|
||||
title="clear"
|
||||
></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
label: string;
|
||||
dateId: string;
|
||||
modelValueDate: string;
|
||||
modelValueTime: string;
|
||||
defaultValueTime: string;
|
||||
disabled?: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "update:modelValueDate", value: string): void;
|
||||
(e: "update:modelValueTime", value: string): void;
|
||||
}>();
|
||||
|
||||
const modelDate = computed({
|
||||
get: () => props.modelValueDate,
|
||||
set: (val: string) => emit("update:modelValueDate", val),
|
||||
});
|
||||
|
||||
const modelTime = computed({
|
||||
get: () => props.modelValueTime,
|
||||
set: (val: string) => emit("update:modelValueTime", val),
|
||||
});
|
||||
|
||||
function clear() {
|
||||
emit("update:modelValueDate", "");
|
||||
emit("update:modelValueTime", props.defaultValueTime);
|
||||
}
|
||||
</script>
|
@@ -43,12 +43,12 @@
|
||||
}}</label>
|
||||
<addressee-selector-component
|
||||
v-model="selectedAddressees"
|
||||
:suggested="userGroups"
|
||||
:suggested="[]"
|
||||
:label="trans(CHILL_TICKET_LIST_FILTER_BY_ADDRESSEES)"
|
||||
id="addresseeSelector"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-6 mb-3">
|
||||
<!-- Filtre par motifs -->
|
||||
<div class="row">
|
||||
<label class="form-label" for="motiveSelector">{{
|
||||
@@ -60,7 +60,7 @@
|
||||
id="motiveSelector"
|
||||
/>
|
||||
|
||||
<div class="mt-1" style="min-height: 2.2em">
|
||||
<div class="mb-2" style="min-height: 2em">
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<span
|
||||
v-for="motive in selectedMotives"
|
||||
@@ -79,43 +79,40 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- Filtre par état actuel -->
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<div class="mb-2">
|
||||
<label class="form-label pe-2" for="currentState">
|
||||
{{ trans(CHILL_TICKET_LIST_FILTER_CURRENT_STATE) }}
|
||||
</label>
|
||||
<toggle-component
|
||||
v-model="isClosedToggled"
|
||||
:on-label="trans(CHILL_TICKET_LIST_FILTER_CLOSED)"
|
||||
:off-label="trans(CHILL_TICKET_LIST_FILTER_OPEN)"
|
||||
:classColor="{
|
||||
on: 'bg-chill-red',
|
||||
off: 'bg-chill-green',
|
||||
}"
|
||||
@update:model-value="handleStateToggle"
|
||||
id="currentState"
|
||||
/>
|
||||
</div>
|
||||
<div class="d-flex gap-3">
|
||||
<div>
|
||||
<label class="form-label pe-2" for="currentState">
|
||||
{{ trans(CHILL_TICKET_LIST_FILTER_CURRENT_STATE) }}
|
||||
</label>
|
||||
<toggle-component
|
||||
v-model="isClosedToggled"
|
||||
:on-label="trans(CHILL_TICKET_LIST_FILTER_CLOSED)"
|
||||
:off-label="trans(CHILL_TICKET_LIST_FILTER_OPEN)"
|
||||
:classColor="{
|
||||
on: 'bg-chill-red',
|
||||
off: 'bg-chill-green',
|
||||
}"
|
||||
@update:model-value="handleStateToggle"
|
||||
id="currentState"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Filtre par état d'urgence -->
|
||||
<div class="col-6">
|
||||
<div class="mb-2">
|
||||
<label class="form-label pe-2" for="emergency">
|
||||
{{ trans(CHILL_TICKET_LIST_FILTER_EMERGENCY) }}
|
||||
</label>
|
||||
<toggle-component
|
||||
v-model="isEmergencyToggled"
|
||||
:on-label="trans(CHILL_TICKET_LIST_FILTER_EMERGENCY)"
|
||||
:off-label="trans(CHILL_TICKET_LIST_FILTER_EMERGENCY)"
|
||||
:classColor="{
|
||||
on: 'bg-warning',
|
||||
off: 'bg-secondary',
|
||||
}"
|
||||
@update:model-value="handleEmergencyToggle"
|
||||
id="emergency"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="form-label pe-2" for="emergency">
|
||||
{{ trans(CHILL_TICKET_LIST_FILTER_EMERGENCY) }}
|
||||
</label>
|
||||
<toggle-component
|
||||
v-model="isEmergencyToggled"
|
||||
:on-label="trans(CHILL_TICKET_LIST_FILTER_EMERGENCY)"
|
||||
:off-label="trans(CHILL_TICKET_LIST_FILTER_EMERGENCY)"
|
||||
:classColor="{
|
||||
on: 'bg-warning',
|
||||
off: 'bg-secondary',
|
||||
}"
|
||||
@update:model-value="handleEmergencyToggle"
|
||||
id="emergency"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -124,6 +121,18 @@
|
||||
<div class="row">
|
||||
<!-- Filtre pour temps de réponse dépassé -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="form-check">
|
||||
<input
|
||||
v-model="filters.byAddresseeToMe"
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
id="stateMe"
|
||||
/>
|
||||
<label class="form-check-label" for="stateMe">
|
||||
{{ trans(CHILL_TICKET_LIST_FILTER_TO_ME) }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input
|
||||
class="form-check-input"
|
||||
@@ -141,48 +150,40 @@
|
||||
{{ trans(CHILL_TICKET_LIST_FILTER_RESPONSE_TIME_WARNING) }}
|
||||
</small>
|
||||
</div>
|
||||
<!-- Filtre par mes tickets -->
|
||||
<!-- Filtre par numéro de ticket -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="d-flex gap-3">
|
||||
<div class="form-check">
|
||||
<input
|
||||
v-model="filters.byAddresseeToMe"
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
id="stateMe"
|
||||
/>
|
||||
<label class="form-check-label" for="stateMe">
|
||||
{{ trans(CHILL_TICKET_LIST_FILTER_TO_ME) }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<label class="form-label pe-2" for="ticketSelector">
|
||||
{{ trans(CHILL_TICKET_LIST_FILTER_BY_TICKET_ID) }}
|
||||
</label>
|
||||
<ticket-selector v-model="filters.byTicketId" id="ticketSelector" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filtre par date de création -->
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="byCreatedAfter" class="form-label">{{
|
||||
trans(CHILL_TICKET_LIST_FILTER_CREATED_AFTER)
|
||||
}}</label>
|
||||
<input
|
||||
type="datetime-local"
|
||||
id="byCreatedAfter"
|
||||
v-model="filters.byCreatedAfter"
|
||||
class="form-control"
|
||||
<date-and-time-selector-component
|
||||
:label="trans(CHILL_TICKET_LIST_FILTER_CREATED_AFTER)"
|
||||
date-id="byCreatedAfter"
|
||||
default-value-time="00:00"
|
||||
:model-value-date="filters.byCreatedAfter"
|
||||
:model-value-time="byCreatedAfterTime"
|
||||
:disabled="filters.byResponseTimeExceeded"
|
||||
@update:modelValueDate="filters.byCreatedAfter = $event"
|
||||
@update:modelValueTime="byCreatedAfterTime = $event"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="byCreatedBefore" class="form-label">{{
|
||||
trans(CHILL_TICKET_LIST_FILTER_CREATED_BEFORE)
|
||||
}}</label>
|
||||
<input
|
||||
type="datetime-local"
|
||||
id="byCreatedBefore"
|
||||
v-model="filters.byCreatedBefore"
|
||||
class="form-control"
|
||||
<date-and-time-selector-component
|
||||
:label="trans(CHILL_TICKET_LIST_FILTER_CREATED_BEFORE)"
|
||||
date-id="byCreatedBefore"
|
||||
default-value-time="23:59"
|
||||
:model-value-date="filters.byCreatedBefore"
|
||||
:model-value-time="byCreatedBeforeTime"
|
||||
:disabled="filters.byResponseTimeExceeded"
|
||||
@update:modelValueDate="filters.byCreatedBefore = $event"
|
||||
@update:modelValueTime="byCreatedBeforeTime = $event"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -218,10 +219,13 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import type { Person } from "ChillPersonAssets/types";
|
||||
import type { Motive, TicketFilterParams, TicketFilters } from "../../../types";
|
||||
import { User, UserGroup, UserGroupOrUser } from "ChillMainAssets/types";
|
||||
import {
|
||||
type Motive,
|
||||
type TicketFilterParams,
|
||||
type TicketFilters,
|
||||
} from "../../../types";
|
||||
import { User, UserGroupOrUser } from "ChillMainAssets/types";
|
||||
|
||||
// Translation
|
||||
import {
|
||||
@@ -234,6 +238,7 @@ import {
|
||||
CHILL_TICKET_LIST_FILTER_ADDRESSEES,
|
||||
CHILL_TICKET_LIST_FILTER_BY_ADDRESSEES,
|
||||
CHILL_TICKET_LIST_FILTER_BY_MOTIVES,
|
||||
CHILL_TICKET_LIST_FILTER_BY_TICKET_ID,
|
||||
CHILL_TICKET_LIST_FILTER_REMOVE,
|
||||
CHILL_TICKET_LIST_FILTER_OPEN,
|
||||
CHILL_TICKET_LIST_FILTER_CLOSED,
|
||||
@@ -254,6 +259,8 @@ import PersonsSelector from "../../TicketApp/components/Person/PersonsSelectorCo
|
||||
import MotiveSelector from "../../TicketApp/components/Motive/MotiveSelectorComponent.vue";
|
||||
import AddresseeSelectorComponent from "../../TicketApp/components/Addressee/AddresseeSelectorComponent.vue";
|
||||
import ToggleComponent from "./ToggleComponent.vue";
|
||||
import TicketSelector from "../../TicketApp/components/Ticket/TicketSelector.vue";
|
||||
import DateAndTimeSelectorComponent from "./DateAndTimeSelectorComponent.vue";
|
||||
|
||||
// Props
|
||||
const props = defineProps<{
|
||||
@@ -267,8 +274,6 @@ const emit = defineEmits<{
|
||||
"filters-changed": [filters: TicketFilterParams];
|
||||
}>();
|
||||
|
||||
const store = useStore();
|
||||
|
||||
// État réactif
|
||||
const filters = ref<TicketFilters>({
|
||||
byCurrentState: ["open"],
|
||||
@@ -277,15 +282,18 @@ const filters = ref<TicketFilters>({
|
||||
byCreatedBefore: "",
|
||||
byResponseTimeExceeded: false,
|
||||
byAddresseeToMe: false,
|
||||
byTicketId: null,
|
||||
});
|
||||
|
||||
const byCreatedAfterTime = ref("00:00");
|
||||
const byCreatedBeforeTime = ref("23:59");
|
||||
|
||||
// Sélection des personnes
|
||||
const selectedPersons = ref<Person[]>([]);
|
||||
const availablePersons = ref<Person[]>(props.availablePersons || []);
|
||||
|
||||
// Sélection des utilisateur assigné
|
||||
const selectedAddressees = ref<UserGroupOrUser[]>([]);
|
||||
const userGroups = computed(() => store.getters.getUserGroups as UserGroup[]);
|
||||
|
||||
// Séléction des créateurs
|
||||
const selectedCreator = ref<User[]>([]);
|
||||
@@ -351,10 +359,10 @@ const handleEmergencyToggle = (value: boolean) => {
|
||||
}
|
||||
};
|
||||
|
||||
// Méthodes
|
||||
const formatDateToISO = (dateString: string): string => {
|
||||
if (!dateString) return dateString;
|
||||
const formatDateToISO = (dateString: string, timeString: string): string => {
|
||||
const [hours, minutes] = timeString.split(":").map(Number);
|
||||
const date = new Date(dateString);
|
||||
date.setHours(hours, minutes, 0, 0);
|
||||
return date.toISOString();
|
||||
};
|
||||
|
||||
@@ -406,11 +414,17 @@ const applyFilters = (): void => {
|
||||
}
|
||||
|
||||
if (filters.value.byCreatedAfter) {
|
||||
apiFilters.byCreatedAfter = formatDateToISO(filters.value.byCreatedAfter);
|
||||
apiFilters.byCreatedAfter = formatDateToISO(
|
||||
filters.value.byCreatedAfter,
|
||||
byCreatedAfterTime.value,
|
||||
);
|
||||
}
|
||||
|
||||
if (filters.value.byCreatedBefore) {
|
||||
apiFilters.byCreatedBefore = formatDateToISO(filters.value.byCreatedBefore);
|
||||
apiFilters.byCreatedBefore = formatDateToISO(
|
||||
filters.value.byCreatedBefore,
|
||||
byCreatedBeforeTime.value,
|
||||
);
|
||||
}
|
||||
|
||||
if (filters.value.byResponseTimeExceeded) {
|
||||
@@ -419,7 +433,12 @@ const applyFilters = (): void => {
|
||||
if (filters.value.byAddresseeToMe) {
|
||||
apiFilters.byAddresseeToMe = true;
|
||||
}
|
||||
|
||||
if (filters.value.byAddresseeToMe) {
|
||||
apiFilters.byAddresseeToMe = true;
|
||||
}
|
||||
if (filters.value.byTicketId) {
|
||||
apiFilters.byTicketId = filters.value.byTicketId;
|
||||
}
|
||||
emit("filters-changed", apiFilters);
|
||||
};
|
||||
|
||||
@@ -431,13 +450,14 @@ const resetFilters = (): void => {
|
||||
byCreatedBefore: "",
|
||||
byResponseTimeExceeded: false,
|
||||
byAddresseeToMe: false,
|
||||
byTicketId: null,
|
||||
};
|
||||
selectedPersons.value = [];
|
||||
selectedCreator.value = [];
|
||||
selectedAddressees.value = [];
|
||||
selectedMotives.value = [];
|
||||
selectedMotive.value = undefined;
|
||||
isClosedToggled.value = true;
|
||||
isClosedToggled.value = false;
|
||||
isEmergencyToggled.value = false;
|
||||
applyFilters();
|
||||
};
|
||||
@@ -446,7 +466,7 @@ const handleResponseTimeExceededChange = (): void => {
|
||||
if (filters.value.byResponseTimeExceeded) {
|
||||
filters.value.byCreatedBefore = "";
|
||||
filters.value.byCreatedAfter = "";
|
||||
isClosedToggled.value = true;
|
||||
isClosedToggled.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
@@ -11,16 +11,6 @@
|
||||
<div class="d-flex align-items-center fw-bold">
|
||||
<i :class="`${actionIcons[history_line.event_type]} me-1`"></i>
|
||||
<span>{{ explainSentence(history_line) }}</span>
|
||||
<span
|
||||
v-if="
|
||||
history_line.event_type === 'add_comment' &&
|
||||
history_line.data.deleted
|
||||
"
|
||||
class="badge bg-danger ms-2"
|
||||
>
|
||||
{{ trans(CHILL_TICKET_TICKET_HISTORY_MASK_COMMENT) }}
|
||||
</span>
|
||||
|
||||
<state-component
|
||||
:new_state="history_line.data.new_state"
|
||||
v-if="history_line.event_type == 'state_change'"
|
||||
@@ -59,10 +49,7 @@
|
||||
/>
|
||||
<comment-component
|
||||
:commentHistory="history_line.data"
|
||||
v-else-if="
|
||||
history_line.event_type == 'add_comment' &&
|
||||
canBeDisplayed(history_line.data)
|
||||
"
|
||||
v-else-if="history_line.event_type == 'add_comment'"
|
||||
/>
|
||||
<addressee-component
|
||||
:addressees="history_line.data.addressees"
|
||||
@@ -105,19 +92,24 @@ import {
|
||||
CHILL_TICKET_TICKET_HISTORY_STATE_CHANGE,
|
||||
CHILL_TICKET_TICKET_HISTORY_EMERGENCY_CHANGE,
|
||||
CHILL_TICKET_TICKET_HISTORY_SET_CALLER,
|
||||
CHILL_TICKET_TICKET_HISTORY_MASK_COMMENT,
|
||||
} from "translator";
|
||||
|
||||
const props = defineProps<{ history?: TicketHistoryLine[] }>();
|
||||
const history = props.history ?? [];
|
||||
const store = useStore();
|
||||
|
||||
const actionIcons = ref(store.getters.getActionIcons);
|
||||
const canBeDisplayed = ref(store.getters.canBeDisplayed);
|
||||
const actionIcons = ref<Record<string, string>>(store.getters.getActionIcons);
|
||||
const removedCommentIds = ref<number[]>(store.getters.getRemovedCommentIds);
|
||||
|
||||
const filteredHistoryLines = computed(() =>
|
||||
history.filter(
|
||||
(line: TicketHistoryLine) => !(line.event_type === "add_person"),
|
||||
(line: TicketHistoryLine) =>
|
||||
line.event_type !== "add_person" &&
|
||||
!(
|
||||
line.event_type == "add_comment" &&
|
||||
line.data.deleted &&
|
||||
!removedCommentIds.value.includes(line.data.id)
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
|
@@ -24,6 +24,8 @@ chill_ticket:
|
||||
addressees: "Par destinataire"
|
||||
by_addressees: "Par destinataire"
|
||||
by_motives: "Par motifs"
|
||||
by_ticket_id: "Par numéro de ticket"
|
||||
ticket_id: "Numéro de ticket"
|
||||
current_state: "État actuel"
|
||||
open: "Ouvert"
|
||||
closed: "Clôturé"
|
||||
@@ -55,7 +57,7 @@ chill_ticket:
|
||||
create_ticket: "Ticket créé"
|
||||
state_change: ""
|
||||
emergency_change: ""
|
||||
mask_comment: "Masqué"
|
||||
mask_comment: "Supprimer"
|
||||
previous_tickets: "Précédents tickets"
|
||||
actions_toolbar:
|
||||
cancel: "Annuler"
|
||||
@@ -67,10 +69,10 @@ chill_ticket:
|
||||
reopen_success: "Rouverture du ticket réussie"
|
||||
reopen_error: "Erreur lors de la rouverture du ticket"
|
||||
visible_comment:
|
||||
success: "Commentaire visible"
|
||||
success: "Commentaire restauré"
|
||||
mask_comment:
|
||||
success: "Commentaire masqué"
|
||||
hint: "Ce commentaire est masqué; il n'est visible que par vous."
|
||||
success: "Commentaire supprimé"
|
||||
hint: "Ce commentaire a été supprimé."
|
||||
edit_comment:
|
||||
title: "Éditer le commentaire"
|
||||
success: "Commentaire modifié"
|
||||
|
Reference in New Issue
Block a user