From bedc39f1ce54e6acc90aef30e3d2e4555896854e Mon Sep 17 00:00:00 2001
From: Julien Touchais <5978-julien.touchais@users.noreply.forgemia.inra.fr>
Date: Thu, 27 Jun 2024 17:33:13 +0200
Subject: [PATCH] refactor(base-components): :recycle: use component `v-model`
 for BaseRadioFieldset (pre-Vue 3.4 syntax)

---
 src/components/BaseRadioFieldset.vue | 40 +++++++++-------------------
 src/components/InteractionBoard.vue  | 14 +++-------
 src/views/HomeView.vue               |  2 +-
 3 files changed, 17 insertions(+), 39 deletions(-)

diff --git a/src/components/BaseRadioFieldset.vue b/src/components/BaseRadioFieldset.vue
index c1bb2ad..0dc3bc5 100644
--- a/src/components/BaseRadioFieldset.vue
+++ b/src/components/BaseRadioFieldset.vue
@@ -1,8 +1,4 @@
 <script setup lang="ts" generic="T">
-/**
- * Vue imports
- */
-import { ref } from 'vue'
 /**
  * Components imports
  */
@@ -12,33 +8,28 @@ import RadioButton from 'primevue/radiobutton'
  */
 import { get as _get } from 'lodash-es'
 
-defineProps<{
-  /** Text to display as the legend of the fieldset. */
-  legend?: string
+const props = defineProps<{
   /** The values available as options for selection. */
   values: T[]
-  /**
-   * Path to a `value` property to use as the value of an option,
-   * defaults to the option itself when not defined.
-   */
+  /** The currently selected value. */
+  selectionModel?: T[keyof T]
+  /** Text to display as the legend of the fieldset. */
+  legend?: string
+  /** Path to a `value` property to use as the value of an option,
+   * defaults to the option itself when not defined. */
   dataFieldPath?: string
-  /**
-   * Path to a `value` property to use as the label of an option.
-   */
+  /** Path to a `value` property to use as the label of an option. */
   labelFieldPath?: string
 }>()
 
 defineEmits<{
-  /** Event emitted when selected value changes. */
-  change: [value: any]
+  /** Event used to update the `v-model:selectionModel` value. */
+  'update:selectionModel': [selectionModel: typeof props.selectionModel]
 }>()
 
 defineSlots<{
   /** Custom item appearance (input & label). */
   item: (props: {
-    /** The data selected with the radio, in the `dataFieldPath` field of the
-     * selected entry. */
-    selectedData: any
     /** The value of the entry to display. */
     currentValue: T
   }) => any
@@ -48,11 +39,6 @@ defineSlots<{
     currentValue: T
   }) => any
 }>()
-
-/**
- * The currently selected value.
- */
-const selectedData = ref<any>()
 </script>
 
 <template>
@@ -65,11 +51,11 @@ const selectedData = ref<any>()
       :key="index"
       class="flex cursor-pointer items-center gap-2 pl-4 text-lg"
     >
-      <slot name="item" :selected-data="selectedData" :current-value="value">
+      <slot name="item" :current-value="value">
         <RadioButton
-          v-model="selectedData"
+          :model-value="selectionModel"
           :value="dataFieldPath ? _get(value, dataFieldPath) : value"
-          @update:model-value="$emit('change', selectedData)"
+          @update:model-value="(value) => $emit('update:selectionModel', value)"
         />
         <slot name="item-label" :current-value="value">
           {{
diff --git a/src/components/InteractionBoard.vue b/src/components/InteractionBoard.vue
index a6ffd6a..e76b4ba 100644
--- a/src/components/InteractionBoard.vue
+++ b/src/components/InteractionBoard.vue
@@ -84,15 +84,6 @@ watch(
   }
 )
 
-const updateSelection1 = (newSelection: any) => {
-  selectedValue1.value = newSelection
-  selectedValue2.value = undefined
-}
-
-const updateSelection2 = (newSelection: any) => {
-  selectedValue2.value = newSelection
-}
-
 const dedupedInteractionList1 = computed(() =>
   _uniqBy(props.interactionList, props.selectionFieldPath1)
 )
@@ -132,10 +123,11 @@ const selectedValue2 = ref<any>()
       class="relative my-auto rounded-lg border-2 border-solid p-2 pl-0 pt-4"
     >
       <BaseRadioFieldset
+        v-model:selection-model="selectedValue1"
         :legend="selectionFieldLegend1"
         :values="dedupedInteractionList1"
         :data-field-path="selectionFieldPath1"
-        @change="updateSelection1"
+        @update:selection-model="selectedValue2 = undefined"
       >
         <template #item-label="{ currentValue }">
           <slot name="item-label-1" :current-value="currentValue">{{
@@ -150,10 +142,10 @@ const selectedValue2 = ref<any>()
       class="relative my-auto rounded-lg border-2 border-solid p-2 pl-0 pt-4"
     >
       <BaseRadioFieldset
+        v-model:selection-model="selectedValue2"
         :legend="selectionFieldLegend2"
         :values="filteredInteractionList"
         :data-field-path="selectionFieldPath2"
-        @change="updateSelection2"
       >
         <template #item-label="{ currentValue }">
           <slot name="item-label-2" :current-value="currentValue">{{
diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue
index 9ff1e67..dfdf8c4 100644
--- a/src/views/HomeView.vue
+++ b/src/views/HomeView.vue
@@ -84,12 +84,12 @@ const selectedSpeciesId = ref<number>()
       <form class="relative rounded-lg border-2 border-solid p-2 pl-0 pt-4">
         <BaseRadioFieldset
           v-if="speciesList"
+          v-model:selection-model="selectedSpeciesId"
           class="mb-2 max-h-[35vh] overflow-auto"
           legend="Species"
           :values="speciesList"
           data-field-path="id"
           label-field-path="name"
-          @change="(speciesId: number) => (selectedSpeciesId = speciesId)"
         >
           <template #item-label="{ currentValue }">
             <span class="italic">
-- 
GitLab