فهرست منبع

colored benevole selection

tripeur 4 سال پیش
والد
کامیت
bd560ef3fe

+ 2 - 0
.env.development

@@ -0,0 +1,2 @@
+VUE_APP_TITLE=[test] BDLG Planner 
+VUE_APP_API_URL=https://bdlg-planner.jaquin.fr/

+ 21 - 12
src/assets/css/chip.css

@@ -123,19 +123,28 @@
   color: #ffffff;
   background-color: var(--color-accent-500);
 }
-.chip--info {
-  color: #282e3a;
-  background-color: #a3d4f0;
+.chip.info {
+  background-color: var(--color-primary-400);
 }
-.chip--success {
-  color: #282e3a;
-  background-color: #a5f2d8;
+.chip.success {
+  background-color: hsl(160, 75%, 80%);
 }
-.chip--warning {
-  color: #282e3a;
-  background-color: #ffe3cc;
+.chip.success > .chip-remove-btn {
+  background-color: hsl(160, 75%, 60%);
+  color: var(--color-neutral-200);
 }
-.chip--error {
-  color: #282e3a;
-  background-color: #f9ccd4;
+.chip.warning {
+  background-color: hsl(27, 100%, 90%);
+}
+.chip.warning > .chip-remove-btn {
+  background-color: hsl(27, 100%, 70%);
+  color: var(--color-neutral-200);
+}
+
+.chip.error {
+  background-color: hsl(349, 79%, 89%);
+}
+.chip.error > .chip-remove-btn {
+  background-color: hsl(349, 79%, 69%);
+  color: var(--color-neutral-200);
 }

+ 83 - 71
src/assets/css/multiple-select.css

@@ -1,11 +1,11 @@
 .input-control {
-display: inline-block;
-position: relative;
+  display: inline-block;
+  position: relative;
 }
 .select-multiple {
-display: block;
-width: 100%;
-position: relative;
+  display: block;
+  width: 100%;
+  position: relative;
 }
 .select-multiple > .dropdown-options {
   display: none;
@@ -15,13 +15,13 @@ position: relative;
   position: absolute;
   width: 100%;
   background-color: white;
-  }
+}
 .select-multiple.select-multiple--expanded > .dropdown-options {
   display: block;
 }
 .select-multiple.select-multiple--expanded > .dropdown-options > div {
   line-height: 2rem;
-  font-size: .9rem;;
+  font-size: 0.9rem;
   cursor: pointer;
   -webkit-transition: 0.1s ease-in-out;
   transition: 0.1s ease-in-out;
@@ -30,76 +30,88 @@ position: relative;
 }
 
 .dropdown-options > div.select--checked {
-  position:relative;
+  position: relative;
   font-weight: bold;
   color: var(--color-neutral-100);
   background-color: #f8f9fb;
 }
 .dropdown-options > div.select--active {
-background-color: #e0e8ec;
+  background-color: #e0e8ec;
 }
 .dropdown-options > div:hover {
-background-color: #f0f4f6;  
-}
-.dropdown-options  > div:before {
-content: " ";
-background-color: white;
-background-size: 18px;
-height: 18px;
-width: 0px;
-border-radius: 4px;
-display: inline-block;
-margin: 8px;
-}
-.dropdown-options.pickable > div:before{
-width: 18px;
-border-radius: 4px;
-border: solid 1px var(--color-accent-600);
+  background-color: #f0f4f6;
+}
+.dropdown-options > div:before {
+  content: " ";
+  background-color: white;
+  background-size: 18px;
+  height: 18px;
+  width: 0px;
+  border-radius: 4px;
+  display: inline-block;
+  margin: 8px;
+}
+.dropdown-options.pickable > div:before {
+  width: 18px;
+  border-radius: 4px;
+  border: solid 1px var(--color-accent-600);
 }
 .dropdown-options.pickable > div.select--checked:before {
   background-color: var(--color-accent-600);
 }
-.dropdown-options.pickable > div.select--checked:after{
+.dropdown-options.pickable > div.select--checked:after {
   position: absolute;
   content: "";
   border: 2px solid transparent;
   border-right-color: white;
   border-bottom-color: white;
-  width:8px;
+  width: 8px;
   height: 14px;
-  left:13px;
-  top:8px;  
+  left: 13px;
+  top: 8px;
   transform: rotate(37deg);
 }
+.dropdown-options.pickable > div.info {
+  background-color: var(--color-primary-400);
+}
+.dropdown-options.pickable > div.success {
+  background-color: #a5f2d8;
+}
+.dropdown-options.pickable > div.warning {
+  background-color: #ffe3cc;
+}
+.dropdown-options.pickable > div.error {
+  background-color: #f9ccd4;
+}
 .select-multiple > .select-multiple-value {
-all: initial;
-display: block;
-position:relative;
-color: var(--color-neutral-100);
-cursor: pointer;
-width: 100%;
-border: none;
-margin: 0;
-padding: 0.2rem 0.5rem;
-font-size: 0.875rem;
--webkit-appearance: none;
--moz-appearance: none;
-appearance: none;
-box-shadow: 0 -1px 0 0 var(--color-accent-700) inset;
-background-color: var(--color-accent-950);
-box-sizing: border-box;
--webkit-transition: 0.1s ease-in-out;
-transition: 0.1s ease-in-out;
-font-family: Roboto, Helvetica Neue, Helvetica, Arial, sans-serif;
-line-height: 1.3rem;
-padding-right: 2rem;
--webkit-transition-property: box-shadow, border;
-transition-property: box-shadow, border;
+  all: initial;
+  display: block;
+  position: relative;
+  color: var(--color-neutral-100);
+  cursor: pointer;
+  width: 100%;
+  border: none;
+  margin: 0;
+  padding: 0.2rem 0.5rem;
+  font-size: 0.875rem;
+  -webkit-appearance: none;
+  -moz-appearance: none;
+  appearance: none;
+  box-shadow: 0 -1px 0 0 var(--color-accent-700) inset;
+  background-color: var(--color-accent-950);
+  box-sizing: border-box;
+  -webkit-transition: 0.1s ease-in-out;
+  transition: 0.1s ease-in-out;
+  font-family: Roboto, Helvetica Neue, Helvetica, Arial, sans-serif;
+  line-height: 1.3rem;
+  padding-right: 2rem;
+  -webkit-transition-property: box-shadow, border;
+  transition-property: box-shadow, border;
 }
 .select-multiple.select-multiple--expanded > .select-multiple-value::after,
-.select-multiple > .select-multiple-value::after{
+.select-multiple > .select-multiple-value::after {
   content: "expand_less";
-  font-family: 'Material Icons';
+  font-family: "Material Icons";
   font-weight: normal;
   font-style: normal;
   font-size: 1.5rem;
@@ -109,32 +121,32 @@ transition-property: box-shadow, border;
   display: inline-block;
   color: var(--color-accent-400);
   position: absolute;
-  top:4px;
-  right:4px;
+  top: 4px;
+  right: 4px;
 }
-.select-multiple > .select-multiple-value::after{
-content: "expand_more";
+.select-multiple > .select-multiple-value::after {
+  content: "expand_more";
 }
 .select-multiple > .select-multiple-value:hover {
-cursor: pointer;
-background-color: var(--color-accent-850);
+  cursor: pointer;
+  background-color: var(--color-accent-850);
 }
 .select-multiple-value > .chip {
-  margin-right:4px;
-  margin-bottom:4px;
+  margin-right: 4px;
+  margin-bottom: 4px;
 }
 .select-multiple-input {
-border: 0;
-background: transparent;
-font-size: 0.875rem;
-line-height: 1.4rem;
+  border: 0;
+  background: transparent;
+  font-size: 0.875rem;
+  line-height: 1.4rem;
 }
-.select-multiple >.select-multiple-value:focus-within {
-box-shadow: 0 0 0 2px var(--color-accent-700);
-border-color: transparent;
-background-color: var(--color-accent-950);
+.select-multiple > .select-multiple-value:focus-within {
+  box-shadow: 0 0 0 2px var(--color-accent-700);
+  border-color: transparent;
+  background-color: var(--color-accent-950);
 }
 .select-multiple-input:focus,
 .select-multiple-input:focus-visible {
-outline: 0;
+  outline: 0;
 }

+ 49 - 4
src/components/EditeurCreneau.vue

@@ -125,6 +125,7 @@
         class="s6"
         :modelValue="creneau.penibility"
         @input="inputListener($event, 'penibility')"
+        style="display: none"
       />
     </div>
   </div>
@@ -141,6 +142,8 @@ import dayjs from "dayjs";
 
 import "@/assets/css/editor-panel.css";
 import { MutationTypes } from "@/store/Mutations";
+import Benevole from "@/models/Benevole";
+import Competence from "@/models/Competence";
 
 // TODO Understand why the component only syncro after a first edition of the date
 export default defineComponent({
@@ -235,13 +238,49 @@ export default defineComponent({
       return !isNaN(parseFloat(this.duree));
     },
     autocompleteBenevolesList(): Array<AutocompleteOptions> {
-      return this.$store.state.benevoleList.map((benevole) => {
+      const precursor = this.$store.state.benevoleList
+        .map((benevole) => {
+          const score = this.getbenevoleScore(benevole);
+
+          return {
+            id: benevole.id + "",
+            name: benevole.fullname,
+            score,
+          };
+        })
+        .sort((a, b) => {
+          const s = a.score - b.score;
+          return s == 0 ? a.name.localeCompare(b.name) : s;
+        });
+      const output = precursor.map((o) => {
+        let classes = "";
+        if (o.score == 3) {
+          classes = "error";
+        }
+        if (o.score == 2) {
+          classes = "warning";
+        }
+        if (o.score == 1) {
+          classes = "warning";
+        }
         return {
-          id: benevole.id + "",
-          name: benevole.fullname,
-          img: "benevole",
+          id: o.id,
+          name: o.name,
+          class: classes,
         };
       });
+      return output;
+    },
+    competenceList(): Array<Competence> {
+      const output = [];
+      for (const idStr of this.competencesStrIdList) {
+        const id = parseInt(idStr);
+        if (id) {
+          const c = this.$store.getters.getCompetenceById(id);
+          if (c) output.push(c);
+        }
+      }
+      return output;
     },
     autocompleteCompetencesList(): Array<AutocompleteOptions> {
       return this.$store.state.competenceList.map((competence) => {
@@ -250,6 +289,12 @@ export default defineComponent({
     },
   },
   methods: {
+    getbenevoleScore(benevole: Benevole): number {
+      const scoreList = this.competenceList.map((c) =>
+        benevole.competenceIdList.includes(c.id) ? 0 : c.score
+      );
+      return scoreList.length == 0 ? 0 : Math.max(...scoreList);
+    },
     updateDates: function (): void {
       if (this.creneau && this.validDuree && this.validStart) {
         if (Math.abs(this.startDate.getTime() - this.creneau.start.getTime()) > 1000)

+ 13 - 6
src/components/SelectChipInput.vue

@@ -7,7 +7,7 @@
     <div ref="container" class="select-multiple" :class="{ 'select-multiple--expanded': expanded }">
       <div class="select-multiple-value" @click="openDropDown">
         <span v-if="checkedItems.length === 0"></span>
-        <div v-for="item of displayedItems" class="chip" :key="item.id">
+        <div v-for="item of displayedItems" class="chip" :class="item.classes" :key="item.id">
           <span class="chip-label">{{ item.text }}</span>
           <button
             aria-label="Clear"
@@ -30,10 +30,13 @@
       <div class="dropdown-options pickable">
         <div
           v-for="(item, index) in filteredItems"
-          :class="{
-            'select--checked': item.isChecked,
-            'select--active': index == activeIndex,
-          }"
+          :class="[
+            {
+              'select--checked': item.isChecked,
+              'select--active': index == activeIndex,
+            },
+            item.classes,
+          ]"
           :key="item.value"
           @click="toggle(item.index, $event)"
           v-html="highlight(item.text)"
@@ -52,6 +55,7 @@ interface selectItem {
   isChecked: boolean;
   value: string;
   text: string;
+  classes: string;
 }
 export default defineComponent({
   name: "selectChip",
@@ -118,19 +122,22 @@ export default defineComponent({
     updateItems(): void {
       this.items = this.autocompleteList.map(
         (o: AutocompleteValues | string, idx: number): selectItem => {
-          let id: string, txt: string;
+          let id: string, txt: string, classes: string;
           if (typeof o == "object") {
             id = "id" in o ? o.id : o;
             txt = "name" in o ? o.name : id;
+            classes = o.class ?? "";
           } else {
             id = o;
             txt = o;
+            classes = "";
           }
           return {
             index: idx,
             isChecked: this.modelValue.includes(id),
             value: id,
             text: txt,
+            classes,
           };
         }
       );

+ 1 - 1
src/models/AutocompleteOptions.ts

@@ -1,5 +1,5 @@
 export default interface AutocompleteValues {
   id: string;
   name: string;
-  img?: string;
+  class?: string;
 }

+ 3 - 0
src/models/Competence.ts

@@ -49,6 +49,9 @@ export default class Competence {
   static getBox(v: boolean): string {
     return `<i class="material-icons">${v ? "check_box" : "check_box_outline_blank"}</i>`;
   }
+  get score(): number {
+    return this.isPreference ? 1 : this.isTeachable ? 2 : 3;
+  }
   get overflowDescription(): string {
     // TODO implement tooltiped description
     return this.description;

+ 10 - 2
src/models/Creneau.ts

@@ -47,7 +47,15 @@ class Creneau implements ICreneau {
   }
   competencesIdList: number[];
   description: string;
-  isMeal: boolean;
+
+  _isMeal = false;
+  public get isMeal(): boolean {
+    return this._isMeal;
+  }
+  public set isMeal(value: boolean) {
+    this._isMeal = value;
+    this.event.bgColor = value ? "gray" : undefined;
+  }
   fixedAttendee: boolean;
 
   constructor(obj: ICreneau) {
@@ -110,7 +118,7 @@ class Creneau implements ICreneau {
       dayjs(this.event.end).format("HH:mm")
     );
   }
-  toString() {
+  toString(): string {
     return `Créneau[titre:${this.title},\tHoraire:${this.horaire}]`;
   }
   updateEventContent(): void {

+ 1 - 1
src/views/Home.vue

@@ -44,7 +44,7 @@ export default defineComponent({
         html: `Chargement des données du planning "${version.name}"`,
         displayLength: Infinity,
       });
-      this.fetchPlanningVersions(`${API_URL}api/evenements/${version.uuid}`).then((_) => {
+      this.fetchPlanningVersions(`${API_URL}api/evenements/${version.uuid}`).then(() => {
         toast.dismiss();
         Toast({
           html: `Planning "${version.name}" chargé`,

+ 0 - 6
src/views/Planning.vue

@@ -4,12 +4,6 @@
       <div class="timelime-control">
         <h1>Planning global de l'événement</h1>
         <div class="actions">
-          <button class="btn icon small primary">
-            <i class="material-icons">upload_file</i>
-          </button>
-          <button class="btn icon small primary">
-            <i class="material-icons">save</i>
-          </button>
           <button
             class="btn small secondary"
             @click="createCreneau"