ManageRegistration.vue 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. <template>
  2. <dots v-if="loading" />
  3. <div v-else class="container">
  4. <div>
  5. <h3>Liste de demande d'inscription des bénévoles</h3>
  6. <div class="actions">
  7. <button class="btn small primary" @click="importSelected">
  8. <i class="material-icons">input</i>Importer la selection
  9. </button>
  10. <button class="btn small error" @click="deleteSelected">
  11. <i class="material-icons">delete_forever</i>Supprimer la selection
  12. </button>
  13. </div>
  14. <table>
  15. <thead>
  16. <tr>
  17. <th @click="selectAll">
  18. <i class="material-icons">{{ topBox }}</i>
  19. </th>
  20. <th>Nom</th>
  21. <th>Email</th>
  22. </tr>
  23. </thead>
  24. <tbody>
  25. <tr v-for="b in inscriptions" :key="b.id">
  26. <td @click="toggle(b.id)">
  27. <i class="material-icons">{{ checkbox(b.id) }}</i>
  28. </td>
  29. <td @click="display(b.id)">{{ b.name }}, {{ b.surname }}</td>
  30. <td @click="display(b.id)">{{ b.email }}</td>
  31. </tr>
  32. </tbody>
  33. </table>
  34. </div>
  35. <div class="benevole-preview">
  36. <div v-if="benevole">
  37. <h3>Demande d'inscription</h3>
  38. <div class="field"><span>Nom</span>{{ benevole.surname }}</div>
  39. <div class="field"><span>Prénom</span>{{ benevole.name }}</div>
  40. <div class="field"><span>Téléphone</span>{{ benevole.phone }}</div>
  41. <div class="field"><span>Email</span>{{ benevole.email }}</div>
  42. <div class="field"><span>Commentaire</span><br />{{ benevole.comment }}</div>
  43. <div>
  44. <h4>Competences & Préférence</h4>
  45. <div class="chip" v-for="id in benevole.competenceIdList" :key="id">
  46. <span class="chip-label">{{ getCompetenceName(id) }}</span>
  47. </div>
  48. </div>
  49. </div>
  50. <div v-else>Cliquer sur un ligne</div>
  51. </div>
  52. </div>
  53. </template>
  54. <script lang="ts">
  55. import Benevole, { BenevoleJSON } from "@/models/Benevole";
  56. import { defineComponent } from "vue";
  57. import dots from "@/components/Dots.vue";
  58. import { MutationTypes } from "@/store/Mutations";
  59. const API_URL = process.env.VUE_APP_API_URL;
  60. export default defineComponent({
  61. components: { dots },
  62. data() {
  63. return {
  64. inscriptions: [] as Array<BenevoleJSON>,
  65. loading: true,
  66. selected: [] as Array<number>,
  67. benevole: null as null | BenevoleJSON,
  68. };
  69. },
  70. methods: {
  71. toggle(id: number) {
  72. if (this.selected.includes(id)) {
  73. this.selected = this.selected.filter((o) => o != id);
  74. } else {
  75. this.selected.push(id);
  76. }
  77. },
  78. display(id: number) {
  79. this.benevole = this.inscriptions.find((b) => b.id == id) ?? null;
  80. },
  81. checkbox(id: number) {
  82. return this.selected.includes(id) ? "check_box" : "check_box_outline_blank";
  83. },
  84. selectAll() {
  85. this.selected =
  86. this.selected.length == this.inscriptions.length
  87. ? []
  88. : (this.inscriptions.map((b) => b.id) as Array<number>);
  89. },
  90. importSelected() {
  91. for (const benevole of this.selectedInscriptions) {
  92. this.$store.commit(
  93. MutationTypes.addBenevole,
  94. Benevole.fromJSON({ ...benevole, id: undefined })
  95. );
  96. }
  97. this.deleteSelected();
  98. },
  99. deleteSelected() {
  100. for (const benevole of this.selectedInscriptions) {
  101. fetch(`${API_URL}api/inscription/${this.uuid}/${benevole.id}`, { method: "DELETE" }).then(
  102. (res) => {
  103. if (res.status == 200) {
  104. return res.json();
  105. } else {
  106. throw new Error(res.statusText);
  107. }
  108. }
  109. );
  110. }
  111. this.inscriptions = this.inscriptions.filter((b) => b.id && !this.selected.includes(b.id));
  112. this.selected = [];
  113. },
  114. getCompetenceName(id: number): string {
  115. return this.$store.getters.getCompetenceById(id)?.name ?? "";
  116. },
  117. },
  118. computed: {
  119. uuid(): string {
  120. return this.$store.state.evenement.uuid;
  121. },
  122. selectedInscriptions(): Array<BenevoleJSON> {
  123. return this.inscriptions.filter((b) => b.id && this.selected.includes(b.id));
  124. },
  125. topBox(): string {
  126. if (this.selected.length == 0) {
  127. return "check_box_outline_blank";
  128. } else {
  129. if (this.selected.length == this.inscriptions.length) {
  130. return "check_box";
  131. } else {
  132. return "indeterminate_check_box";
  133. }
  134. }
  135. },
  136. },
  137. mounted() {
  138. fetch(`${API_URL}api/inscription/${this.uuid}`)
  139. .then((res) => {
  140. if (res.status == 200) {
  141. return res.json();
  142. } else {
  143. throw new Error(res.statusText);
  144. }
  145. })
  146. .then((data: Array<BenevoleJSON>) => {
  147. this.inscriptions = data;
  148. this.loading = false;
  149. });
  150. },
  151. });
  152. </script>
  153. <style scoped>
  154. .container {
  155. display: flex;
  156. gap: 32px;
  157. justify-content: center;
  158. align-items: flex-start;
  159. }
  160. @media screen and (min-width: 769px) {
  161. .container {
  162. gap: 8px;
  163. }
  164. }
  165. .benevole-preview {
  166. padding: 12px;
  167. width: 400px;
  168. box-shadow: 0 0 2px 2px var(--color-neutral-600);
  169. }
  170. .benevole-preview > div > div {
  171. padding: 8px;
  172. }
  173. .field > span {
  174. font-weight: bold;
  175. display: inline-block;
  176. min-width: 100px;
  177. }
  178. .field > span:after {
  179. content: " :";
  180. }
  181. .chip {
  182. margin-right: 4px;
  183. margin-bottom: 4px;
  184. }
  185. .actions {
  186. display: inline-flex;
  187. justify-content: left;
  188. flex-wrap: wrap;
  189. margin-bottom: 12px;
  190. }
  191. .actions > .btn {
  192. margin-right: 4px;
  193. margin-bottom: 4px;
  194. }
  195. table {
  196. max-width: 800px;
  197. width: calc(100vw - 690px);
  198. border-collapse: collapse;
  199. }
  200. td,
  201. th {
  202. padding: 0.5rem;
  203. width: calc(50% - 24px - 1rem);
  204. }
  205. tr > *:first-child {
  206. width: calc(24px + 1rem);
  207. cursor: pointer;
  208. }
  209. tr {
  210. border-bottom: 1px solid #ddd;
  211. }
  212. tr:nth-child(even) {
  213. background-color: #eeeeee;
  214. }
  215. tbody tr:hover {
  216. background: var(--color-neutral-800);
  217. }
  218. thead > tr {
  219. border-bottom-width: 2px;
  220. }
  221. </style>