Olivier Massot 3 месяцев назад
Родитель
Сommit
badef4bf73

+ 2 - 1
assets/css/vue-date-picker.scss

@@ -1,7 +1,8 @@
 // @see https://vue3datepicker.com/customization/theming/
 // [!] Sass variables overriding does not work in scoped mode
 
-.dp__theme_light, .dp__theme_dark {
+.dp__theme_light,
+.dp__theme_dark {
   --dp-primary-color: rgb(var(--v-theme-primary)) !important;
   --dp-primary-text-color: rgb(var(--v-theme-on-primary)) !important;
   --dp-secondary-color: rgb(var(--v-theme-neutral-strong)) !important;

+ 2 - 1
components/Form/Parameter/EducationTiming.vue

@@ -28,5 +28,6 @@ const proxyEntity = computed({
   set: (value) => emit('update:entity', value),
 })
 
-const getAsserts = (key: string) => getAssertUtils(EducationTiming.getAsserts(), key)
+const getAsserts = (key: string) =>
+  getAssertUtils(EducationTiming.getAsserts(), key)
 </script>

+ 2 - 1
components/Form/Parameter/ResidenceArea.vue

@@ -29,5 +29,6 @@ const proxyEntity = computed({
   set: (value) => emit('update:entity', value),
 })
 
-const getAsserts = (key: string) => getAssertUtils(ResidenceArea.getAsserts(), key)
+const getAsserts = (key: string) =>
+  getAssertUtils(ResidenceArea.getAsserts(), key)
 </script>

+ 9 - 13
components/Ui/Button/HelloAssoConnect.vue

@@ -17,19 +17,15 @@ Bouton de connexion à HelloAsso
   </button>
 </template>
 
-<script setup lang="ts">
-
-
-
-</script>
+<script setup lang="ts"></script>
 
 <style scoped lang="scss">
 .HaAuthorizeButton {
   align-items: center;
   -webkit-box-pack: center;
   -ms-flex-pack: center;
-  background-color: #FFFFFF;
-  border: 0.0625rem solid #4B3FCF;
+  background-color: #ffffff;
+  border: 0.0625rem solid #4b3fcf;
   border-radius: 0.125rem;
   display: -webkit-box;
   display: -ms-flexbox;
@@ -37,7 +33,7 @@ Bouton de connexion à HelloAsso
   padding: 0;
 }
 .HaAuthorizeButton:disabled {
-  background-color: #4B3FCF;
+  background-color: #4b3fcf;
   border-color: transparent;
   cursor: not-allowed;
 }
@@ -50,18 +46,18 @@ Bouton de connexion à HelloAsso
   width: 60px;
 }
 .HaAuthorizeButtonTitle {
-  background-color: #4B3FCF;
-  color: #FFFFFF;
+  background-color: #4b3fcf;
+  color: #ffffff;
   font-size: 1rem;
   font-weight: 700;
   padding: 0.78125rem 1.5rem;
 }
 .HaAuthorizeButton:disabled .HaAuthorizeButtonTitle {
-  background-color: #4B3FCF;
-  color: #9A9DA8;
+  background-color: #4b3fcf;
+  color: #9a9da8;
 }
 .HaAuthorizeButton:not(:disabled):hover .HaAuthorizeButtonTitle,
 .HaAuthorizeButton:not(:disabled):focus .HaAuthorizeButtonTitle {
-  background-color: #4B3FCF;
+  background-color: #4b3fcf;
 }
 </style>

+ 3 - 2
components/Ui/Input/TreeSelect.vue

@@ -163,7 +163,6 @@ interface SelectItem {
   level: number
 }
 
-
 const props = defineProps({
   modelValue: {
     type: Array as PropType<string[]>,
@@ -277,7 +276,9 @@ const expandParentsOfSelectedItems = () => {
   expandedSubcategories.value.clear()
 
   for (const selectedId of props.modelValue) {
-    const item = normalizedItems.value.find((i) => i.value === Number(selectedId))
+    const item = normalizedItems.value.find(
+      (i) => i.value === Number(selectedId),
+    )
     if (!item) continue
 
     let parentId = null

+ 3 - 3
config/abilities/pages/helloasso.yaml

@@ -3,6 +3,6 @@ helloasso_page:
   conditions:
     - { function: organizationHasAnyModule, parameters: ['HelloAsso'] }
     - {
-      function: accessHasAnyRoleAbility,
-      parameters: [{ action: 'read', subject: 'helloasso' }],
-    }
+        function: accessHasAnyRoleAbility,
+        parameters: [{ action: 'read', subject: 'helloasso' }],
+      }

+ 3 - 3
config/theme.ts

@@ -36,7 +36,7 @@ interface Theme {
     'on-info': string
     artist: string
     school: string
-    'standout': string
+    standout: string
     'on-standout': string
   }
 }
@@ -90,7 +90,7 @@ export const lightTheme: Theme = {
     info: '#3c8dbc',
     'on-info': '#ffffff',
 
-    'standout': '#f39c12',
+    standout: '#f39c12',
     'on-standout': '#ffffff',
 
     artist: '#fac20a',
@@ -146,7 +146,7 @@ export const darkTheme: Theme = {
     info: '#3c8dbc',
     'on-info': '#ffffff',
 
-    'standout': '#f39c12',
+    standout: '#f39c12',
     'on-standout': '#ffffff',
 
     artist: '#fac20a',

+ 1 - 1
models/HelloAsso/ConnectionRequest.ts

@@ -1,4 +1,4 @@
-import { Uid, Str, Num  } from 'pinia-orm/dist/decorators'
+import { Uid, Str, Num } from 'pinia-orm/dist/decorators'
 import { IdField } from '~/models/decorators'
 import ApiResource from '~/models/ApiResource'
 

+ 1 - 1
models/HelloAsso/HelloAsso.ts

@@ -1,4 +1,4 @@
-import { Num, Uid, Str  } from 'pinia-orm/dist/decorators'
+import { Num, Uid, Str } from 'pinia-orm/dist/decorators'
 import ApiResource from '~/models/ApiResource'
 import { IdField } from '~/models/decorators'
 

+ 1 - 1
models/HelloAsso/UnlinkRequest.ts

@@ -1,4 +1,4 @@
-import { Uid, Num  } from 'pinia-orm/dist/decorators'
+import { Uid, Num } from 'pinia-orm/dist/decorators'
 import { IdField } from '~/models/decorators'
 import ApiResource from '~/models/ApiResource'
 

+ 1 - 4
nuxt.config.ts

@@ -247,10 +247,7 @@ export default defineNuxtConfig({
   ignore: [process.env.NUXT_ENV === 'prod' ? 'pages/dev/*' : ''],
 
   prepare: {
-    scripts: [
-      'prepare/buildIndex.ts',
-      'prepare/compileAbilitiesConfig.ts'
-    ],
+    scripts: ['prepare/buildIndex.ts', 'prepare/compileAbilitiesConfig.ts'],
   },
 
   compatibilityDate: '2025-03-10',

+ 94 - 58
pages/freemium/dashboard.vue

@@ -6,70 +6,92 @@
         <v-col cols="12" md="7">
           <v-card>
             <v-tabs v-model="tab" class="tabs-title">
-              <v-tab value="future">{{$t('futur_event')}}</v-tab>
-              <v-tab value="past">{{$t('past_event')}}</v-tab>
+              <v-tab value="future">{{ $t('futur_event') }}</v-tab>
+              <v-tab value="past">{{ $t('past_event') }}</v-tab>
             </v-tabs>
 
-            <v-btn color="primary" to="events/new" class="ml-5 mt-5">{{$t('add_event')}}</v-btn>
+            <v-btn color="primary" to="events/new" class="ml-5 mt-5">{{
+              $t('add_event')
+            }}</v-btn>
 
             <v-tabs-window v-model="tab">
               <v-tabs-window-item value="future">
-                <UiLoadingPanel v-if="statusUpcomingEvents == FETCHING_STATUS.PENDING" />
+                <UiLoadingPanel
+                  v-if="statusUpcomingEvents == FETCHING_STATUS.PENDING"
+                />
 
                 <UiEventList
-                  v-if="statusUpcomingEvents == FETCHING_STATUS.SUCCESS && upcomingEvents?.items"
+                  v-if="
+                    statusUpcomingEvents == FETCHING_STATUS.SUCCESS &&
+                    upcomingEvents?.items
+                  "
                   :events="upcomingEvents.items"
                   :pagination="upcomingEvents.pagination"
                   @load="loadUpcomingEvents"
                   @edit="editEvent"
                 />
                 <span v-if="upcomingEvents.items.length == 0" class="no_event">
-                  {{$t('no_future_event')}}
+                  {{ $t('no_future_event') }}
                 </span>
               </v-tabs-window-item>
               <v-tabs-window-item value="past">
-                <UiLoadingPanel v-if="statusPastEvents == FETCHING_STATUS.PENDING" />
+                <UiLoadingPanel
+                  v-if="statusPastEvents == FETCHING_STATUS.PENDING"
+                />
 
                 <UiEventList
-                  v-if="statusPastEvents == FETCHING_STATUS.SUCCESS && pastEvents?.items"
+                  v-if="
+                    statusPastEvents == FETCHING_STATUS.SUCCESS &&
+                    pastEvents?.items
+                  "
                   :events="pastEvents.items"
                   :pagination="pastEvents.pagination"
                   @load="loadPastEvents"
                   @edit="editEvent"
                 />
                 <span v-if="pastEvents.items.length == 0" class="no_event">
-                  {{$t('no_past_event')}}
+                  {{ $t('no_past_event') }}
                 </span>
               </v-tabs-window-item>
             </v-tabs-window>
-
           </v-card>
         </v-col>
 
         <!-- Bloc structure -->
         <v-col cols="12" md="5">
-          <v-card v-if="statusOrganization == FETCHING_STATUS.SUCCESS" class="pa-5">
-            <v-card-title class="text-h6" >
-              <v-icon icon="fa fa-hotel" class="text-button icon-hotel"  />
-              <span class="organization_title">{{$t('my_organization')}}</span>
+          <v-card
+            v-if="statusOrganization == FETCHING_STATUS.SUCCESS"
+            class="pa-5"
+          >
+            <v-card-title class="text-h6">
+              <v-icon icon="fa fa-hotel" class="text-button icon-hotel" />
+              <span class="organization_title">{{
+                $t('my_organization')
+              }}</span>
             </v-card-title>
             <v-card-text>
-              <div><strong>{{$t('name')}} :</strong> {{ organization?.name }}</div>
-              <div><strong>{{$t('email')}} :</strong> {{ organization?.email }}</div>
+              <div>
+                <strong>{{ $t('name') }} :</strong> {{ organization?.name }}
+              </div>
+              <div>
+                <strong>{{ $t('email') }} :</strong> {{ organization?.email }}
+              </div>
             </v-card-text>
           </v-card>
 
           <v-btn block class="mb-2 btn btn_edit_orga" to="organization">
-            <i class="fa fa-pen mr-2" />{{$t('edit_organization')}}
+            <i class="fa fa-pen mr-2" />{{ $t('edit_organization') }}
           </v-btn>
 
           <v-btn block class="text-black btn btn_trial" @click="startTrial">
-            <span><v-icon icon="fa fa-ticket" /> {{$t('try_premium_light')}}<br /> {{$t('30_days_free')}}</span>
+            <span
+              ><v-icon icon="fa fa-ticket" /> {{ $t('try_premium_light')
+              }}<br />
+              {{ $t('30_days_free') }}</span
+            >
           </v-btn>
-
         </v-col>
       </v-row>
-
     </v-container>
 
     <LayoutDialogTrialAlreadyDid
@@ -80,23 +102,26 @@
 </template>
 
 <script setup lang="ts">
-
-import Query from "~/services/data/Query";
-
-import {type Ref, ref} from 'vue'
-import {useEntityFetch} from "~/composables/data/useEntityFetch";
-import Organization from "~/models/Freemium/Organization";
-import Event from "~/models/Freemium/Event";
-import type {AsyncData} from "#app";
-import OrderBy from "~/services/data/Filters/OrderBy";
-import {FETCHING_STATUS, ORDER_BY_DIRECTION, TIME_STRATEGY} from "~/types/enum/data";
-import PageFilter from "~/services/data/Filters/PageFilter";
-import TimeFilter from "~/services/data/Filters/TimeFilter";
-import Country from "~/models/Core/Country";
-import DateUtils from "~/services/utils/dateUtils";
-import UrlUtils from "~/services/utils/urlUtils";
-import {useApiLegacyRequestService} from "~/composables/data/useApiLegacyRequestService";
-import {useAdminUrl} from "~/composables/utils/useAdminUrl";
+import Query from '~/services/data/Query'
+
+import { type Ref, ref } from 'vue'
+import { useEntityFetch } from '~/composables/data/useEntityFetch'
+import Organization from '~/models/Freemium/Organization'
+import Event from '~/models/Freemium/Event'
+import type { AsyncData } from '#app'
+import OrderBy from '~/services/data/Filters/OrderBy'
+import {
+  FETCHING_STATUS,
+  ORDER_BY_DIRECTION,
+  TIME_STRATEGY,
+} from '~/types/enum/data'
+import PageFilter from '~/services/data/Filters/PageFilter'
+import TimeFilter from '~/services/data/Filters/TimeFilter'
+import Country from '~/models/Core/Country'
+import DateUtils from '~/services/utils/dateUtils'
+import UrlUtils from '~/services/utils/urlUtils'
+import { useApiLegacyRequestService } from '~/composables/data/useApiLegacyRequestService'
+import { useAdminUrl } from '~/composables/utils/useAdminUrl'
 
 definePageMeta({
   name: 'freemium_dashboard_page',
@@ -106,16 +131,24 @@ definePageMeta({
 const runtimeConfig = useRuntimeConfig()
 const { fetch, fetchCollection } = useEntityFetch()
 const { apiRequestService } = useApiLegacyRequestService()
-const {makeAdminUrl} = useAdminUrl()
+const { makeAdminUrl } = useAdminUrl()
 const tab = ref(null)
 const upcomingPage = ref(1)
 const pastPage = ref(1)
 const showDialogTrialAlReadyDid: Ref<boolean> = ref(false)
 
 //Fetch
-const { data: organization, status:statusOrganization } = fetch(Organization)
-const { data: upcomingEvents, status: statusUpcomingEvents, refresh: refreshUpcomingEvents } = fetchEvents()
-const { data: pastEvents, status: statusPastEvents, refresh: refreshPastEvents } = fetchEvents(true)
+const { data: organization, status: statusOrganization } = fetch(Organization)
+const {
+  data: upcomingEvents,
+  status: statusUpcomingEvents,
+  refresh: refreshUpcomingEvents,
+} = fetchEvents()
+const {
+  data: pastEvents,
+  status: statusPastEvents,
+  refresh: refreshPastEvents,
+} = fetchEvents(true)
 
 /**
  * Charge une page des événements à venir
@@ -147,14 +180,20 @@ function editEvent(eventId: number) {
  * Récupère la liste des événements
  * @param past
  */
-function fetchEvents(past:boolean = false){
+function fetchEvents(past: boolean = false) {
   const today = computed(() => DateUtils.formatIsoShortDate(new Date()))
-  const query =
-    new Query(
-      new OrderBy('datetimeStart', past ? ORDER_BY_DIRECTION.DESC : ORDER_BY_DIRECTION.ASC),
-      new PageFilter(past ? pastPage : upcomingPage, ref(5)),
-      new TimeFilter('datetimeStart', today, past ? TIME_STRATEGY.BEFORE : TIME_STRATEGY.AFTER)
-    )
+  const query = new Query(
+    new OrderBy(
+      'datetimeStart',
+      past ? ORDER_BY_DIRECTION.DESC : ORDER_BY_DIRECTION.ASC,
+    ),
+    new PageFilter(past ? pastPage : upcomingPage, ref(5)),
+    new TimeFilter(
+      'datetimeStart',
+      today,
+      past ? TIME_STRATEGY.BEFORE : TIME_STRATEGY.AFTER,
+    ),
+  )
 
   return fetchCollection(Event, null, query)
 }
@@ -181,37 +220,34 @@ onUnmounted(() => {
   useRepo(Event).flush()
   useRepo(Country).flush()
 })
-
 </script>
 
 <style scoped lang="scss">
-
-.tabs-title{
+.tabs-title {
   margin-top: 20px;
   padding-left: 20px;
   background-color: rgb(var(--v-theme-neutral));
-  .v-tab--selected{
+  .v-tab--selected {
     color: rgb(var(--v-theme-on-neutral--clickable));
   }
 }
 
-
 .v-card {
   margin-bottom: 16px;
   color: rgb(var(--v-theme-on-neutral));
 }
 
-.v-card-text{
-  div{
+.v-card-text {
+  div {
     line-height: 2;
   }
 }
 
-.organization_title{
+.organization_title {
   font-weight: 500;
 }
 
-.icon-hotel{
+.icon-hotel {
   margin: 0 5px 4px 0;
 }
 
@@ -245,7 +281,7 @@ onUnmounted(() => {
   color: rgb(var(--v-theme-on-neutral)) !important;
 }
 
-.no_event{
+.no_event {
   padding: 25px;
   font-size: 16px;
 }

+ 2 - 1
pages/freemium/organization.vue

@@ -172,7 +172,8 @@ onUnmounted(() => {
   useRepo(Country).flush()
 })
 
-const getAsserts = (key: string) => getAssertUtils(Organization.getAsserts(), key)
+const getAsserts = (key: string) =>
+  getAssertUtils(Organization.getAsserts(), key)
 </script>
 
 <style scoped lang="scss">

+ 6 - 9
pages/helloasso/callback.vue

@@ -15,8 +15,8 @@ Page cible du callback après authentification via la mire d'autorisation HelloA
       </div>
 
       <div v-else class="ma-4">
-        <div>{{ $t('an_error_occured')}}</div>
-        <div>{{ $t('please_contact_support')}}</div>
+        <div>{{ $t('an_error_occured') }}</div>
+        <div>{{ $t('please_contact_support') }}</div>
       </div>
     </v-app>
   </NuxtLayout>
@@ -49,13 +49,10 @@ if (!route.query.code) {
 
 const authorizationCode: Ref<string> = ref(route.query.code as string)
 
-const connectionRequest: ConnectionRequest = em.newInstance(
-  ConnectionRequest,
-  {
-    organizationId: organizationProfile.id,
-    authorizationCode: authorizationCode.value,
-  },
-)
+const connectionRequest: ConnectionRequest = em.newInstance(ConnectionRequest, {
+  organizationId: organizationProfile.id,
+  authorizationCode: authorizationCode.value,
+})
 
 const error: Ref<boolean> = ref(false)
 

+ 4 - 1
services/data/entityManager.ts

@@ -180,7 +180,10 @@ class EntityManager {
    * @param model
    * @param id
    */
-  public find<T extends typeof ApiResource>(model: T, id: number | string): InstanceType<T> {
+  public find<T extends typeof ApiResource>(
+    model: T,
+    id: number | string,
+  ): InstanceType<T> {
     const repository = this.getRepository(model)
     return repository.find(id) as T
   }

+ 1 - 3
services/layout/menuBuilder/basicomptaMenuBuilder.ts

@@ -10,9 +10,7 @@ export default class BasicomptaMenuBuilder extends AbstractMenuBuilder {
 
   build(): MenuItem | null {
     // cf droit : https://ressources-opentalent.atlassian.net/wiki/spaces/SPEC/pages/32637034/Acc+s+basi+compta+pour+les+structures+de+la+CMF#Acces-a-Basicompta-pour-les-administrateurs
-    if (
-      this.ability.can('display', 'basicompta_page')
-    ) {
+    if (this.ability.can('display', 'basicompta_page')) {
       return this.createItem(
         'basicompta_admin',
         { name: 'fas fa-suitcase' },

+ 1 - 3
services/layout/menuBuilder/helloAssoMenuBuilder.ts

@@ -9,9 +9,7 @@ export default class BasicomptaMenuBuilder extends AbstractMenuBuilder {
   static override readonly menuName = 'HelloAsso'
 
   build(): MenuItem | null {
-    if (
-        this.ability.can('display', 'helloasso_page')
-    ) {
+    if (this.ability.can('display', 'helloasso_page')) {
       return this.createItem(
         'helloasso_admin',
         { name: 'fas fa-link' },

+ 1 - 1
stores/helloasso.ts

@@ -14,6 +14,6 @@ export const useHelloAssoStore = defineStore('helloasso', () => {
 
   return {
     authorizationCode,
-    setAuthorizationCode
+    setAuthorizationCode,
   }
 })

+ 8 - 6
tests/units/services/rights/abilityBuilder.test.ts

@@ -10,15 +10,17 @@ import type OrganizationProfile from '~/models/Organization/OrganizationProfile'
 vi.mock('~/config/abilities/config-precompiled', () => {
   return {
     default: {
-      'subject1': {
+      subject1: {
         action: 'display',
-        conditions: [{ function: 'accessHasAnyProfile', parameters: ['guardian'] }]
+        conditions: [
+          { function: 'accessHasAnyProfile', parameters: ['guardian'] },
+        ],
       },
-      'subject2': {
+      subject2: {
         action: 'display',
-        conditions: [{ function: 'organizationIsSchool' }]
-      }
-    }
+        conditions: [{ function: 'organizationIsSchool' }],
+      },
+    },
   }
 })