ManageRegistration.vue 6.1 KB

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