Browse Source

Implement print card page

tripeur 4 years ago
parent
commit
ab2e069778

+ 1 - 1
src/PlannerApp.vue

@@ -60,7 +60,7 @@ const tabs: Array<HeaderLink> = [
   { to: "/planner/planning", name: "Planning" },
   { to: "/planner/contraintes", name: "Gestion des contraintes" },
   { to: "/planner/benevoles", name: "Gestion des bénévoles" },
-  { to: "/planner/planningIndividuel", name: "Planning Individuel" },
+  { to: "/planner/planningResultat", name: "Planning Individuel" },
   { to: "/planner/planningImprimmable", name: "Planning Terrain" },
 ];
 export default defineComponent({

+ 48 - 0
src/components/BenevoleCard.vue

@@ -0,0 +1,48 @@
+<template>
+  <div class="benevole-card">
+    <div class="benevole-card--title">{{ benevole.name }}</div>
+    <div class="benevole-card--content" v-for="creneau in creneaux" :key="creneau.id">
+      <creneau-viewer :creneau="creneau" />
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+import Benevole from "@/models/Benevole";
+import Creneau from "@/models/Creneau";
+import creneauViewer from "@/components/PrintableCreneauViewer.vue";
+import { defineComponent, PropType } from "vue";
+
+export default defineComponent({
+  components: { creneauViewer },
+  props: { benevole: { type: Object as PropType<Benevole>, required: true } },
+  data() {
+    return {};
+  },
+  computed: {
+    creneaux(): Array<Creneau> {
+      return this.benevole
+        ? this.$store.state.creneauList
+            .filter((o) => o.benevoleIdList.includes(this.benevole.id))
+            .sort((a, b) => a.start.getTime() - b.start.getTime())
+        : [];
+    },
+  },
+});
+</script>
+
+<style>
+.benevole-card {
+  border: #000 solid 1px;
+}
+.benevole-card--title {
+  color: #fff;
+  background: #000;
+  font-weight: bold;
+  padding: 4px;
+}
+.benevole-card--content {
+  padding: 4px;
+  border-bottom: #000 1px solid;
+}
+</style>

+ 2 - 52
src/components/CreneauViewer.vue → src/components/CollapsableCreneauViewer.vue

@@ -65,9 +65,11 @@
 <script lang="ts">
 import Benevole from "@/models/Benevole";
 import Creneau from "@/models/Creneau";
+import CreneauView from "@/mixins/creneauView";
 import { defineComponent, PropType } from "vue";
 
 export default defineComponent({
+  mixins: [CreneauView],
   props: {
     creneau: { type: Object as PropType<Creneau> },
     currentBenevole: { type: Object as PropType<Benevole> },
@@ -88,53 +90,6 @@ export default defineComponent({
       }
       return "Aucune description pour ce créneau";
     },
-    creneauBenevoleList(): Array<Benevole> {
-      if (this.creneau) {
-        return this.getBenevoleforCreneau(this.creneau);
-      }
-      return [];
-    },
-    sameParentCreneau(): Array<Creneau> {
-      if (this.creneau) {
-        const c = this.creneau;
-        const filter = (creneau: Creneau) =>
-          creneau.id !== c.id && creneau.ressourceId === c.ressourceId;
-        return this.$store.state.creneauList.filter(filter);
-      }
-      return [];
-    },
-    prevCreneau(): Creneau | undefined {
-      if (this.creneau) {
-        const creneau = this.creneau;
-        return this.sameParentCreneau.reduce((acc: Creneau | undefined, c: Creneau) => {
-          const timeDiff = creneau.start.getTime() - c.end.getTime();
-          if (0 <= timeDiff && timeDiff < 60 * 30 * 1000) {
-            return c;
-          }
-          return acc;
-        }, undefined);
-      }
-      return undefined;
-    },
-    nextCreneau(): Creneau | undefined {
-      if (this.creneau) {
-        const creneau = this.creneau;
-        return this.sameParentCreneau.reduce((acc: Creneau | undefined, c: Creneau) => {
-          const timeDiff = c.start.getTime() - creneau.end.getTime();
-          if (0 <= timeDiff && timeDiff < 60 * 30 * 1000) {
-            return c;
-          }
-          return acc;
-        }, undefined);
-      }
-      return undefined;
-    },
-    prevCreneauBenevoleList(): Array<Benevole> {
-      return this.prevCreneau ? this.getBenevoleforCreneau(this.prevCreneau) : [];
-    },
-    nextCreneauBenevoleList(): Array<Benevole> {
-      return this.nextCreneau ? this.getBenevoleforCreneau(this.nextCreneau) : [];
-    },
   },
   methods: {
     onClick: function () {
@@ -143,11 +98,6 @@ export default defineComponent({
     onClickContact: function (benevole: Benevole) {
       this.$emit("contact", benevole);
     },
-    getBenevoleforCreneau(creneau: Creneau): Array<Benevole> {
-      return creneau.benevoleIdList
-        .map((id) => this.$store.getters.getBenevoleById(id))
-        .filter((o) => o !== undefined) as Array<Benevole>;
-    },
     collapse(element: HTMLElement): void {
       element.style.height = "0";
     },

+ 64 - 0
src/components/NavigationPanel.vue

@@ -0,0 +1,64 @@
+<template>
+  <div class="panel-container">
+    <div class="panel" ref="panel">
+      <div
+        v-for="(o, idx) in options"
+        class="panel-item"
+        :class="{ selected: modelValue == o.id }"
+        @click="change(o.id)"
+        :key="idx"
+      >
+        {{ o.title }}
+      </div>
+    </div>
+    <div class="panel-container-main" :style="{ marginLeft: width + 'px' }">
+      <slot></slot>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, PropType } from "vue";
+
+export type NavigationOption = { id: string; title: string };
+export default defineComponent({
+  props: {
+    options: { type: Array as PropType<Array<NavigationOption>>, default: () => [] },
+    modelValue: { type: String, default: () => "" },
+  },
+  methods: {
+    change(v: string) {
+      this.$emit("update:modelValue", v);
+    },
+  },
+  data() {
+    return { width: 0 };
+  },
+  mounted() {
+    this.$nextTick(() => (this.width = (this.$refs.panel as HTMLDivElement).offsetWidth));
+  },
+});
+</script>
+
+<style scoped>
+.panel-container {
+  width: 100%;
+  position: relative;
+}
+.panel {
+  height: calc(100% - 3.5rem);
+  border-right: solid 1px var(--color-neutral-800);
+  position: fixed;
+  margin: -8px 8px 0 -8px;
+  min-width: 200px;
+}
+.panel-item {
+  padding: 16px;
+  white-space: nowrap;
+  cursor: pointer;
+}
+.panel-item.selected {
+  background: var(--color-accent-600);
+  color: var(--color-neutral-100);
+}
+</style>

+ 21 - 0
src/components/PrintableCreneauViewer.vue

@@ -0,0 +1,21 @@
+<template>
+  <div>{{ creneau.title }} {{ creneau.fromTo }}</div>
+  <div v-if="creneau.description"><strong>Description: </strong> {{ creneau.description }}</div>
+  <div v-if="nextCreneauBenevoleList.length > 0">
+    <strong>Qui te remplacera? </strong>
+    <span v-for="benevole in nextCreneauBenevoleList" :key="benevole.id">
+      {{ benevole.shortame }},
+    </span>
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent } from "vue";
+
+import CreneauView from "@/mixins/creneauView";
+export default defineComponent({
+  mixins: [CreneauView],
+});
+</script>
+
+<style></style>

+ 65 - 0
src/mixins/creneauView.ts

@@ -0,0 +1,65 @@
+import Benevole from "@/models/Benevole";
+import Creneau from "@/models/Creneau";
+import { defineComponent, PropType } from "vue";
+
+export default defineComponent({
+  props: {
+    creneau: { type: Object as PropType<Creneau> },
+  },
+  computed: {
+    creneauBenevoleList(): Array<Benevole> {
+      if (this.creneau) {
+        return this.getBenevoleforCreneau(this.creneau);
+      }
+      return [];
+    },
+    sameParentCreneau(): Array<Creneau> {
+      if (this.creneau) {
+        const c = this.creneau;
+        const filter = (creneau: Creneau) =>
+          creneau.id !== c.id && creneau.ressourceId === c.ressourceId;
+        return this.$store.state.creneauList.filter(filter);
+      }
+      return [];
+    },
+    prevCreneau(): Creneau | undefined {
+      if (this.creneau) {
+        const creneau = this.creneau;
+        return this.sameParentCreneau.reduce((acc: Creneau | undefined, c: Creneau) => {
+          const timeDiff = creneau.start.getTime() - c.end.getTime();
+          if (0 <= timeDiff && timeDiff < 60 * 30 * 1000) {
+            return c;
+          }
+          return acc;
+        }, undefined);
+      }
+      return undefined;
+    },
+    nextCreneau(): Creneau | undefined {
+      if (this.creneau) {
+        const creneau = this.creneau;
+        return this.sameParentCreneau.reduce((acc: Creneau | undefined, c: Creneau) => {
+          const timeDiff = c.start.getTime() - creneau.end.getTime();
+          if (0 <= timeDiff && timeDiff < 60 * 30 * 1000) {
+            return c;
+          }
+          return acc;
+        }, undefined);
+      }
+      return undefined;
+    },
+    prevCreneauBenevoleList(): Array<Benevole> {
+      return this.prevCreneau ? this.getBenevoleforCreneau(this.prevCreneau) : [];
+    },
+    nextCreneauBenevoleList(): Array<Benevole> {
+      return this.nextCreneau ? this.getBenevoleforCreneau(this.nextCreneau) : [];
+    },
+  },
+  methods: {
+    getBenevoleforCreneau(creneau: Creneau): Array<Benevole> {
+      return creneau.benevoleIdList
+        .map((id) => this.$store.getters.getBenevoleById(id))
+        .filter((o) => o !== undefined) as Array<Benevole>;
+    },
+  },
+});

+ 4 - 4
src/router/main.ts

@@ -3,7 +3,7 @@ import Evenement from "../views/Evenement.vue";
 import Planning from "@/views/Planning.vue";
 import CompetenceManager from "@/views/CompetenceManager.vue";
 import BenevoleManager from "@/views/BenevoleManager.vue";
-import PlanningPersonnel from "@/views/PlanningPersonnel.vue";
+import PlanningOutput from "@/views/PlanningOutput.vue";
 import PrintablePlanning from "@/views/PrintablePlanning.vue";
 import Help from "@/views/Help.vue";
 import Home from "@/views/Home.vue";
@@ -35,9 +35,9 @@ const routes: Array<RouteRecordRaw> = [
     component: BenevoleManager,
   },
   {
-    path: "/planner/planningIndividuel",
-    name: "planningIndividuel",
-    component: PlanningPersonnel,
+    path: "/planner/planningResultat",
+    name: "planningOutput",
+    component: PlanningOutput,
   },
   {
     path: "/planner/planningImprimmable",

+ 33 - 70
src/views/BenevoleManager.vue

@@ -1,52 +1,31 @@
 <template>
-  <div class="benevole-page">
-    <div class="panel">
-      <div class="panel-item" :class="{ selected: show == 'benevole' }" @click="show = 'benevole'">
-        Bénévoles
-      </div>
-      <div
-        class="panel-item"
-        :class="{ selected: show == 'questionnaire' }"
-        @click="show = 'questionnaire'"
-      >
-        Gestion du questionnaire
-      </div>
-      <div
-        class="panel-item"
-        :class="{ selected: show == 'inscriptions' }"
-        @click="show = 'inscriptions'"
-      >
-        Validations des inscriptions
-      </div>
-    </div>
-    <div class="benevole-page-main">
-      <div class="page" v-show="show == 'benevole'">
-        <data-table
-          class="data-table"
-          title="Liste des bénévoles"
-          :data="data"
-          :clickable="true"
-          :loadingAnimation="loading"
-          :exportable="false"
-          locale="fr"
-          @row-click="onRowClick"
-          :customButtons="customButton"
-        ></data-table>
-        <editeur-benevole
-          :benevole="currentBenevole"
-          @create="createBenevole"
-          @delete="deleteBenevole"
-        />
-        <input type="file" ref="loadcsv" @change="importBenevoleTemplate" style="display: none" />
-      </div>
-      <editeur-questionnaire
-        v-if="show == 'questionnaire'"
-        :competences="competenceList"
-        :uuid="uuid"
+  <navigation v-model="show" :options="navOption">
+    <div class="page" v-show="show == 'benevole'">
+      <data-table
+        class="data-table"
+        title="Liste des bénévoles"
+        :data="data"
+        :clickable="true"
+        :loadingAnimation="loading"
+        :exportable="false"
+        locale="fr"
+        @row-click="onRowClick"
+        :customButtons="customButton"
+      ></data-table>
+      <editeur-benevole
+        :benevole="currentBenevole"
+        @create="createBenevole"
+        @delete="deleteBenevole"
       />
-      <manage-registration v-if="show == 'inscriptions'" />
+      <input type="file" ref="loadcsv" @change="importBenevoleTemplate" style="display: none" />
     </div>
-  </div>
+    <editeur-questionnaire
+      v-if="show == 'questionnaire'"
+      :competences="competenceList"
+      :uuid="uuid"
+    />
+    <manage-registration v-if="show == 'inscriptions'" />
+  </navigation>
 </template>
 
 <script lang="ts">
@@ -54,6 +33,7 @@ import Competence from "@/models/Competence";
 import EditeurBenevole from "@/components/EditeurBenevole.vue";
 import EditeurQuestionnaire from "@/components/EditeurQuestionnaire.vue";
 import ManageRegistration from "@/components/ManageRegistration.vue";
+import Navigation from "@/components/NavigationPanel.vue";
 import DataTable, {
   CustomButton,
   DataTableData,
@@ -67,10 +47,16 @@ import dayjs from "dayjs";
 import Toast from "@/utils/Toast";
 
 const csvDefaultcolumn = "id,prenom,nom,telephone,email,commentaire";
+const navOption = [
+  { id: "benevole", title: "Bénévoles" },
+  { id: "questionnaire", title: "Gestion du questionnaire" },
+  { id: "inscriptions", title: "Validations des inscriptions" },
+];
 export default defineComponent({
   name: "EditeurCreneau",
-  components: { DataTable, EditeurBenevole, ManageRegistration, EditeurQuestionnaire },
+  components: { DataTable, EditeurBenevole, ManageRegistration, EditeurQuestionnaire, Navigation },
   data: () => ({
+    navOption,
     show: "benevole",
     columns: [
       {
@@ -285,13 +271,6 @@ export default defineComponent({
 </script>
 
 <style scoped>
-.benevole-page {
-  width: 100%;
-  position: relative;
-}
-.benevole-page-main {
-  margin-left: 240px;
-}
 .page {
   display: flex;
   flex-direction: column;
@@ -316,20 +295,4 @@ export default defineComponent({
     margin-top: 32px;
   }
 }
-
-.panel {
-  height: calc(100% - 3.5rem);
-  border-right: solid 1px var(--color-neutral-800);
-  position: fixed;
-  margin: -8px 8px 0 -8px;
-}
-.panel-item {
-  padding: 16px;
-  white-space: nowrap;
-  cursor: pointer;
-}
-.panel-item.selected {
-  background: var(--color-accent-600);
-  color: var(--color-neutral-100);
-}
 </style>

+ 65 - 0
src/views/PlanningOutput.vue

@@ -0,0 +1,65 @@
+<template>
+  <navigation-panel v-model="show" :options="navOption">
+    <planning v-if="show == 'benevole'" />
+    <div v-if="show == 'card'" class="benevole-container">
+      <benevole-card v-for="(b, idx) in benevoles" :benevole="b" :key="idx" />
+    </div>
+  </navigation-panel>
+</template>
+
+<script lang="ts">
+import { defineComponent } from "vue";
+
+import Planning from "@/views/PlanningPersonnel.vue";
+import NavigationPanel, { NavigationOption } from "@/components/NavigationPanel.vue";
+import BenevoleCard from "@/components/BenevoleCard.vue";
+import Benevole from "@/models/Benevole";
+
+const navOption: Array<NavigationOption> = [
+  { id: "benevole", title: "Bénévoles" },
+  { id: "card", title: "Impression" },
+];
+export default defineComponent({
+  components: { Planning, NavigationPanel, BenevoleCard },
+  data() {
+    return { navOption, show: "card" };
+  },
+  computed: {
+    benevoles(): Array<Benevole> {
+      return [...this.$store.state.benevoleList].sort((a, b) =>
+        a.shortame.localeCompare(b.shortame)
+      );
+    },
+  },
+});
+</script>
+
+<style>
+.benevole-container {
+  break-inside: auto;
+  display: block;
+  border-collapse: collapse;
+}
+@media print {
+  body {
+    -webkit-print-color-adjust: exact; /*chrome & webkit browsers*/
+    color-adjust: exact; /*firefox & IE */
+  }
+  .panel,
+  header,
+  footer {
+    display: none !important;
+  }
+  .panel-container-main {
+    margin-left: auto !important;
+  }
+
+  .benevole-card {
+    display: block;
+    max-width: 100%;
+    break-inside: avoid !important;
+    break-before: always;
+    -webkit-break-before: always;
+  }
+}
+</style>

+ 2 - 2
src/views/PlanningPersonnel.vue

@@ -43,7 +43,7 @@
 </template>
 
 <script lang="ts">
-import CreneauViewer from "../components/CreneauViewer.vue";
+import CreneauViewer from "../components/CollapsableCreneauViewer.vue";
 import AutoCompleteInput from "../components/AutoCompleteInput.vue";
 import { defineComponent } from "vue";
 import Creneau from "@/models/Creneau";
@@ -129,7 +129,7 @@ export default defineComponent({
 });
 </script>
 
-<style scoped>
+<style>
 .container {
   display: flex;
   justify-content: center;