|
|
@@ -1,17 +1,11 @@
|
|
|
# Analyse - 09/2022
|
|
|
|
|
|
-## Workflow du traitement de données
|
|
|
+## Workflow du traitement de données des adresses postales sur la fiche de la structure
|
|
|
|
|
|
Etude du workflow des pages `pages/organization/index.vue` et `pages/organization/address/*`
|
|
|
|
|
|
-### Entités
|
|
|
-
|
|
|
#### Get
|
|
|
|
|
|
-##### Via UiCollection
|
|
|
-
|
|
|
-> Exemple : l'affichage des adresses sur la fiche de la structure
|
|
|
-
|
|
|
La page intègre le component `UiCollection`, qui prend en paramètres :
|
|
|
|
|
|
* la query (récupérée depuis le repo)
|
|
|
@@ -25,44 +19,6 @@ Elle appelle ensuite cette méthode et récupère le `fetchState` et les items s
|
|
|
|
|
|
Enfin, elle passe les items à son slot, qui les utilise pour afficher les données
|
|
|
|
|
|
-
|
|
|
-##### Via UiItemFromUri
|
|
|
-
|
|
|
-> Exemple : l'affichage du pays dans le détail des adresses de la fiche de la structure
|
|
|
-
|
|
|
-Extrait l'id de l'Uri
|
|
|
-
|
|
|
-utilise le `useFetch` natif de nuxt en lui passant en callback un appel à `$dataProvider.invoke`
|
|
|
-
|
|
|
-L'item est ensuite retourné sous forme d'une ComputedRef qui retourne elle-même `queryHelper.getItem`
|
|
|
-
|
|
|
-
|
|
|
-##### Via UiDataTable
|
|
|
-
|
|
|
-Prend en paramètres :
|
|
|
-
|
|
|
-* la query (récupérée depuis le repo)
|
|
|
-* le modèle de l'entity concernée
|
|
|
-* le modèle depuis lequel il est modifié
|
|
|
-* l'id du modèle depuis lequel il est modifié
|
|
|
-
|
|
|
-Utilise `useFetch` en lui passant en callback un appel à `$dataProvider.invoke(type: QUERY_TYPE.MODEL, ...)`
|
|
|
-
|
|
|
-
|
|
|
-##### UiLayoutAlertBarCotisation
|
|
|
-
|
|
|
-Récupère l'état des cotisations avec un `useFetch` auquel on passe en callback un appel à `$dataProvider.invoke({type: QUERY_TYPE.DEFAULT, ...})`
|
|
|
-
|
|
|
-##### Composable useCountryProvider
|
|
|
-
|
|
|
-Utilise `useFetch` en lui passant en callback un appel à `$dataProvider.invoke(type: QUERY_TYPE.MODEL, ...)`
|
|
|
-
|
|
|
-##### Composable useTypeOfPracticeProvider
|
|
|
-
|
|
|
-Utilise `useFetch` en lui passant en callback un appel à `$dataProvider.invoke(type: QUERY_TYPE.MODEL, ...)`
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
#### Create
|
|
|
|
|
|
##### Page `entity/new.vue`
|
|
|
@@ -149,10 +105,8 @@ L'entry correspond à l'entité dans le store telle que récupérée via le repo
|
|
|
`updateRepository` sera appellée par chaque input qui sont mis à jour
|
|
|
|
|
|
|
|
|
-
|
|
|
#### Edit
|
|
|
|
|
|
-
|
|
|
##### Page `entity/_id.vue`
|
|
|
|
|
|
Idem *create*, excepté que le formulaire est inclus dans une page `entity/_id.vue`
|
|
|
@@ -164,8 +118,81 @@ Parse l'id de l'entité à éditer directement depuis l'url
|
|
|
Passe l'id et le type d'entité à la méthode `getItemToEdit` qui appelle la méthode `$dataProvider.invoke` et retourne une ref `fetchState`.
|
|
|
|
|
|
|
|
|
+
|
|
|
+## Autres Usages
|
|
|
+
|
|
|
+### Entités
|
|
|
+
|
|
|
+##### Via UiCollection
|
|
|
+
|
|
|
+GET
|
|
|
+
|
|
|
+> Exemple : l'affichage des adresses sur la fiche de la structure
|
|
|
+
|
|
|
+La page intègre le component `UiCollection`, qui prend en paramètres :
|
|
|
+
|
|
|
+* la query (récupérée depuis le repo)
|
|
|
+* le modèle de l'entity concernée
|
|
|
+* le modèle d'origine (ici Organization)
|
|
|
+* l'id d'origine (celui de l'orga)
|
|
|
+
|
|
|
+L'`UiCollection` récupère la méthode `getCollection` de `useDataUtils` (à qui elle a passé le `dataProvider`)
|
|
|
+
|
|
|
+Elle appelle ensuite cette méthode et récupère le `fetchState` et les items sous forme de ref
|
|
|
+
|
|
|
+Enfin, elle passe les items à son slot, qui les utilise pour afficher les données
|
|
|
+
|
|
|
+
|
|
|
+##### Via UiItemFromUri
|
|
|
+
|
|
|
+GET
|
|
|
+
|
|
|
+> Exemple : l'affichage du pays dans le détail des adresses de la fiche de la structure
|
|
|
+
|
|
|
+Extrait l'id de l'Uri
|
|
|
+
|
|
|
+utilise le `useFetch` natif de nuxt en lui passant en callback un appel à `$dataProvider.invoke`
|
|
|
+
|
|
|
+L'item est ensuite retourné sous forme d'une ComputedRef qui retourne elle-même `queryHelper.getItem`
|
|
|
+
|
|
|
+
|
|
|
+##### Via UiDataTable
|
|
|
+
|
|
|
+GET
|
|
|
+
|
|
|
+Prend en paramètres :
|
|
|
+
|
|
|
+* la query (récupérée depuis le repo)
|
|
|
+* le modèle de l'entity concernée
|
|
|
+* le modèle depuis lequel il est modifié
|
|
|
+* l'id du modèle depuis lequel il est modifié
|
|
|
+
|
|
|
+Utilise `useFetch` en lui passant en callback un appel à `$dataProvider.invoke(type: QUERY_TYPE.MODEL, ...)`
|
|
|
+
|
|
|
+
|
|
|
+##### UiLayoutAlertBarCotisation
|
|
|
+
|
|
|
+GET
|
|
|
+
|
|
|
+Récupère l'état des cotisations avec un `useFetch` auquel on passe en callback un appel à `$dataProvider.invoke({type: QUERY_TYPE.DEFAULT, ...})`
|
|
|
+
|
|
|
+##### Composable useCountryProvider
|
|
|
+
|
|
|
+GET
|
|
|
+
|
|
|
+Utilise `useFetch` en lui passant en callback un appel à `$dataProvider.invoke(type: QUERY_TYPE.MODEL, ...)`
|
|
|
+
|
|
|
+##### Composable useTypeOfPracticeProvider
|
|
|
+
|
|
|
+GET
|
|
|
+
|
|
|
+Utilise `useFetch` en lui passant en callback un appel à `$dataProvider.invoke(type: QUERY_TYPE.MODEL, ...)`
|
|
|
+
|
|
|
+
|
|
|
##### Composable useMyProfile
|
|
|
|
|
|
+GET / EDIT
|
|
|
+
|
|
|
Propose une méthode pour maj le profile via `$dataPersister.invoke({type: QUERY_TYPE.MODEL, ...})`
|
|
|
|
|
|
|
|
|
@@ -173,13 +200,16 @@ Propose une méthode pour maj le profile via `$dataPersister.invoke({type: QUERY
|
|
|
|
|
|
##### Via UiButtonDelete
|
|
|
|
|
|
-Appelle directement `$dataDeleter.invoke`
|
|
|
+DELETE
|
|
|
|
|
|
+Appelle directement `$dataDeleter.invoke`
|
|
|
|
|
|
|
|
|
|
|
|
#### Cas particulier : UiLayoutHeaderNotification
|
|
|
|
|
|
+GET / EDIT
|
|
|
+
|
|
|
Récupère les notifs depuis l'api via un useFetch avec un callback à `await $dataProvider.invoke({type: QUERY_TYPE.ENUM, enumType})`
|
|
|
|
|
|
Récupère ensuite les notifs depuis le store sous forme de computed ref
|
|
|
@@ -189,26 +219,24 @@ Récupère ensuite les notifs depuis le store sous forme de computed ref
|
|
|
|
|
|
### Enums
|
|
|
|
|
|
-#### Get
|
|
|
-
|
|
|
##### Via UiInputEnum
|
|
|
|
|
|
+GET
|
|
|
+
|
|
|
Récupère l'enum via un useFetch avec un callback à `await $dataProvider.invoke({type: QUERY_TYPE.ENUM, enumType})`
|
|
|
|
|
|
Lorsque les notifications ont été lues, créé un nouvel objet NotificationUser en :
|
|
|
|
|
|
* mettant à jour le store avec `repositoryHelper.persist`
|
|
|
* l'api avec `$dataPersister.invoke(type: QUERY_TYPE.MODEL, ...)`
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+*
|
|
|
|
|
|
### Images
|
|
|
|
|
|
-#### Get
|
|
|
-
|
|
|
##### Via UiImage
|
|
|
|
|
|
+GET
|
|
|
+
|
|
|
Récupère l'image grâce à la méthode `getOne` du composable `useImageProvider` (à qui on a passé le data provider et la config du context)
|
|
|
|
|
|
`getOne` appelle un dataProvider avec le type `QUERY_TYPE.IMAGE` et lui passe les arguments de config de l'image (id, hauteur, largeur)
|
|
|
@@ -217,6 +245,8 @@ En cas d'erreur, retourne une image par défaut.
|
|
|
|
|
|
##### Via UiInputImage
|
|
|
|
|
|
+GET
|
|
|
+
|
|
|
Si un id a été passé aux props, récupère l'objet File via un useFetch avec un
|
|
|
callback à `await $dataProvider.invoke({type: QUERY_TYPE.DEFAULT, url: 'api/files', id: props.existingImageId })`
|
|
|
|
|
|
@@ -225,23 +255,22 @@ On récupère ensuite l'image grâce à la méthode `getOne` du composable `useI
|
|
|
`getOne` appelle un dataProvider avec le type `QUERY_TYPE.IMAGE` et lui passe les arguments de config de l'image (id, hauteur, largeur)
|
|
|
En cas d'erreur, retourne une image par défaut.
|
|
|
|
|
|
-#### Put
|
|
|
-
|
|
|
##### Via UiInputImage
|
|
|
|
|
|
+GET / PUT
|
|
|
+
|
|
|
Met à jour le store avec `repositoryHelper.persist`
|
|
|
|
|
|
Envoie la requête de maj du File avec `$dataPersister.invoke(type: QUERY_TYPE.MODEL, ...)`
|
|
|
|
|
|
-#### Post
|
|
|
-
|
|
|
-##### Via UiInputImage
|
|
|
+POST
|
|
|
|
|
|
Créé un nouvel objet File à sauvegarder
|
|
|
|
|
|
L'envoie à l'API avec `$dataPersister.invoke(type: QUERY_TYPE.FILE, ...)`
|
|
|
|
|
|
|
|
|
+
|
|
|
### Api externes ou routes custom
|
|
|
|
|
|
#### UiInputAutocompleteWithApi
|
|
|
@@ -295,10 +324,12 @@ Appelle la route `/api/dolibarr/account/` via un appel à `$dataProvider.invoke(
|
|
|
##### Data managers
|
|
|
|
|
|
* je pense qu'on devrait sortir le `$nuxt.$loading.start()` du service baseDataManager, c'est pas trop à sa place ici
|
|
|
-* le data deleter ne passe pas par un data processor pour mettre à jour le store. mais est-ce nécessaire au final?
|
|
|
+* le data deleter ne passe pas par un dataProcessor pour mettre à jour le store. mais est-ce nécessaire au final?
|
|
|
* est-ce qu'on devrait pas choisir soit de récupérer les données dans des composables (ex: useTypeOfPracticeProvider, useCountryProvider), soit dans les components? si on maintient les composables, on pourrait
|
|
|
- les mettre dans un sous-dossier? ou même factoriser la méthode?
|
|
|
-
|
|
|
+ les mettre dans un sous-dossier ? ou même factoriser la méthode ?
|
|
|
+* DataPersister L25 : c'est bizarre de stocker l'objet sérialisé dans une de ses propres props non ? on devrait peut-être créer une nouvelle variable et laisser là l'objet DataPersisterArgs
|
|
|
+* ce serait pas mal de passer juste les props nécessaire aux différentes méthodes plutôt que le paquet `queryArgs` à chaque fois, je pense qu'on y verrait plus clair sur qui fait quoi
|
|
|
+* Les services data managers devraient être indépendant de VuexOrm/PiniaOrm, on devrait donc remplacer le param 'query' du data persister par des données sérialisables
|
|
|
|
|
|
##### Forms
|
|
|
|
|
|
@@ -309,7 +340,9 @@ Appelle la route `/api/dolibarr/account/` via un appel à `$dataProvider.invoke(
|
|
|
* plutôt que d'instancier une entité dans la page et de la passer au form, est-ce qu'on ne passerait pas un param 'create' au form? il faudrait lever des erreurs si `create == true & id != null` ou `create == false & id == null`
|
|
|
* comment imposer des propriétés à tous les FormXxxx? Serait-il possible de mettre en place une interface pour l'array props, et de la tester depuis UiForm?
|
|
|
* useError, ligne 7 : je suppose que la docstring est pas la bonne?
|
|
|
-
|
|
|
+* uiForm, L185-188 : je passerais ça dans une méthode `resetEntry` par ex
|
|
|
+* components/Form/Organization/ContactPoint.vue, L62 : est-ce que l'action Back serait pas à sa place avec les actions SUBMIT_TYPE ?
|
|
|
+*
|
|
|
##### Actions des forms
|
|
|
|
|
|
* `actions[SUBMIT_TYPE.SAVE] = { path: `/organization/address/` }` : un moyen de rendre plus explicite que l'url dans path est la page où l'on se rend après l'action?
|
|
|
@@ -320,10 +353,23 @@ Appelle la route `/api/dolibarr/account/` via un appel à `$dataProvider.invoke(
|
|
|
|
|
|
* voir à sortir les services profiles/* et rights/* et à les passer dans les composables (il faudra maj les plugins ability et castl)
|
|
|
* UiItemFromUri, ligne 52 : pqoi ne pas appeller directement `ModelsUtils.extractIdFromUri(uri)`
|
|
|
-* UiInputImage, ligne 120 : est-ce que ce ne serait pas à sa place dans un processor attaché au data provider ça?
|
|
|
+* UiInputImage, ligne 112 : est-ce que ce ne serait pas à sa place dans un processor attaché au data provider QUERY_TYPE.IMAGE ça?
|
|
|
+* pourquoi avoir séparé les pages parameters et organization en deux? devrais-je faire la même chose avec subscription? (ex: pages/organization.vue et pages/parameters/index.vue)
|
|
|
+* component useDataUtils :
|
|
|
+ * on pourrait renommer `getItemToEdit` en `getItem`?
|
|
|
+ * on pourrait ptêt renommer la méthode `createItem` en `getItemCreator` ou un truc du genre, pour expliciter le fait qu'on retourne une méthode, pas qu'on créé directement l'objet
|
|
|
+* page communication : passer getCurrentWebsite dans un service? (s'il n'existe pas déjà)
|
|
|
+* UiCollection : on pourrait pas passer l'entry root plutot que son model+id? est-ce que le terme de parent serait plus précis ou pas ?
|
|
|
+* middleware/auth.ts : on devrait mettre l'uri du front "admin" non?
|
|
|
+* pour gérer les cas comme sur la page subdomains/id_, on pourrait sortir la logique de soumission et validation de UiForm et mettre ça dans un component séparé ou dans un composable? de cette façon, on pourrait utiliser
|
|
|
+ cette logique sans être dans un formulaire classique (boutons, dialog…)
|
|
|
+* détail : dans UiCollection, on pourrait ptêt éviter des confusions en renommant la prop `newLink` en qqchose comme `pageNewUri`, ou `linkToNewPage`, ou même `linkToNew`, mais bon, c'est ptêt pas nécessaire...
|
|
|
+* useValidator : est-ce qu'on ne passerait pas le contenu de ces fonctions dans des services de validation? même chose pour les autres composable qui font des requêtes à l'api ou des calculs testables
|
|
|
|
|
|
### Structure
|
|
|
|
|
|
+#### Entity Manager
|
|
|
+
|
|
|
Mettre en place un "guichet unique" pour les entités, nommé par ex entityManager
|
|
|
|
|
|
Décliner les data-managers en :
|
|
|
@@ -333,7 +379,7 @@ Décliner les data-managers en :
|
|
|
* FileManager (`fileManager`)
|
|
|
* ImageManager (`imageManager`), utile? ou fusionner avec le FileManager?
|
|
|
|
|
|
-Ces managers auraient des méthodes comme : `getRepository` (voir si nécessaire de garder l'étape des repos), `fetch`, `persist`, `delete`, `new` ou `init`, `flush` (?)
|
|
|
+Ces managers auraient des méthodes comme : `getRepository` (voir si nécessaire de garder l'étape des repos), `fetch`, `persist`, `delete`, `new` ou `init`, `flush` (?), `rollback` ou `reset`
|
|
|
|
|
|
Ils seraient responsables de la validation, de l'état de loading, de l'état dirty
|
|
|
|
|
|
@@ -342,3 +388,770 @@ Ils seraient importables depuis un composable du type `useDataManager` ou `useEn
|
|
|
> Incorporer les méthodes de useDataUtils dans ce manager
|
|
|
> Voir si utile de récupérer des méthodes de useForm? Pas sûr, mais l'objectif serait que useForm soit seul à interagir avec le store formState, et aussi le seul à interagir avec.
|
|
|
|
|
|
+L'idée serait que ce que l'on écrit comme ça aujourd'hui :
|
|
|
+
|
|
|
+ const {getItemToEdit} = useDataUtils($dataProvider)
|
|
|
+ const {fetchState} = getItemToEdit(id, Parameters)
|
|
|
+ const repository: VuexRepository<Model> = repositoryHelper.getRepository(Parameters)
|
|
|
+ const query: ComputedRef<Query> = computed(() => repository.query())
|
|
|
+ const entry: ComputedRef<AnyJson> = computed(() => {
|
|
|
+ return queryHelper.getFlattenEntry(query.value, id)
|
|
|
+ })
|
|
|
+
|
|
|
+Puisse s'écrire plus ou moins comme ça :
|
|
|
+
|
|
|
+ const { em } = useEntityManager()
|
|
|
+ { fetchState, entity } = em.fetch(Parameters, id) // où fetchState et entity serait des 'ref'?
|
|
|
+
|
|
|
+Ou même quelque chose comme ça ?
|
|
|
+
|
|
|
+ const { em } = useEntityManager()
|
|
|
+ let fetchState = ref(true)
|
|
|
+ let parameters = ref(null)
|
|
|
+ em.fetch(Parameters, id).onSuccess((e) => { fetchState.value = false; entity.value = e; })
|
|
|
+
|
|
|
+Si on décide finalement de conserver la mécanique actuelle, je propose alors de revoir les termes employés, afin de bien identifier les
|
|
|
+différentes opérations
|
|
|
+
|
|
|
+#### Application aux différents types d'usage
|
|
|
+
|
|
|
+1. Récupération et mise à jour du profil
|
|
|
+2. Affichage des données d'une entité
|
|
|
+3. Affichage d'une collection d'entités
|
|
|
+4. Formulaire de création / édition d'une entité
|
|
|
+5. Population d'un input par un enum
|
|
|
+6. Population d'un input par des entités (ex: liste des pays)
|
|
|
+7. Population d'un input depuis une source externe (ex: adresses)
|
|
|
+8. Affichage / upload d'une image
|
|
|
+9. Téléchargement / upload de fichier
|
|
|
+10. Affichage et éditions des notifications
|
|
|
+11. Validation de données (ex: siret)
|
|
|
+12. Affichage de données issues d'une api externe ou de routes custom (ex: dolibarr, mobyt)
|
|
|
+
|
|
|
+##### 1- Récupération et mise à jour du profil
|
|
|
+
|
|
|
+Actuellement, cette mise à jour se fait dans store/index.js :
|
|
|
+
|
|
|
+ async nuxtServerInit ({ dispatch }, { req }) {
|
|
|
+ await dispatch('initCookies', { req })
|
|
|
+ await dispatch('getUserProfile')
|
|
|
+ },
|
|
|
+
|
|
|
+ async getUserProfile ({ dispatch }) {
|
|
|
+ const myProfile = await this.app.context.$dataProvider.invoke({
|
|
|
+ type: QUERY_TYPE.DEFAULT,
|
|
|
+ url: '/api/my_profile'
|
|
|
+ })
|
|
|
+ await dispatch('profile/access/setProfile', myProfile.data)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+Ici a priori, un simple appel à `Connection.get` pourrait suffire (il faut juste ajouter une méthode get pour les
|
|
|
+url custom, parce que getItem est dédié aux entities). D'autant que le denormalizer des data provider est le denormalizer
|
|
|
+Hydra, ce qui n'est **pas adapté** aux routes comme api/my_profile par ex.
|
|
|
+
|
|
|
+Ça donnerait un truc du genre :
|
|
|
+
|
|
|
+ async getUserProfile ({ dispatch }) {
|
|
|
+ const myProfile = await this.app.context.$connection.get('/api/my_profile')
|
|
|
+ await dispatch('profile/access/setProfile', myProfile)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+##### 2- Affichage des données d'une entité
|
|
|
+
|
|
|
+Exemple de pages/organization.vue :
|
|
|
+
|
|
|
+ const {store, $dataProvider} = useContext()
|
|
|
+ const {getItemToEdit} = useDataUtils($dataProvider)
|
|
|
+ const id = store.state.profile.organization.id
|
|
|
+
|
|
|
+ const {fetchState} = getItemToEdit(id, Organization)
|
|
|
+
|
|
|
+ const repository = repositoryHelper.getRepository(Organization)
|
|
|
+ const query: ComputedRef<Query> = computed(() => repository.query())
|
|
|
+ const entry: ComputedRef<Item> = computed(() => {
|
|
|
+ return queryHelper.getItem(query.value, id)
|
|
|
+ })
|
|
|
+
|
|
|
+ return {
|
|
|
+ entry,
|
|
|
+ fetchState
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+Est-ce qu'on peut espérer quelque chose de ce genre ?
|
|
|
+
|
|
|
+ const { em } = useEntityManager()
|
|
|
+
|
|
|
+ const { fetchState, organization } = em.fetch(Organization, id)
|
|
|
+
|
|
|
+ return {
|
|
|
+ organization,
|
|
|
+ fetchState
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+##### 3- Affichage d'une collection d'entités
|
|
|
+
|
|
|
+Exemple de pages/organization/index.vue :
|
|
|
+
|
|
|
+ <script>
|
|
|
+ function getRepositories () {
|
|
|
+ return {
|
|
|
+ (...)
|
|
|
+ contactPointRepository: repositoryHelper.getRepository(ContactPoint),
|
|
|
+ (...)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ setup () {
|
|
|
+ (...)
|
|
|
+ return {
|
|
|
+ repositories: () => getRepositories(),
|
|
|
+ (...)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ </script>
|
|
|
+
|
|
|
+ <template>
|
|
|
+ <UiCollection
|
|
|
+ :query="repositories().contactPointRepository.query()"
|
|
|
+ :root-model="models().Organization"
|
|
|
+ :root-id="id"
|
|
|
+ :model="models().ContactPoint"
|
|
|
+ newLink="/organization/contact_points/new"
|
|
|
+ >
|
|
|
+ <template #list.item="{items}">
|
|
|
+ (...)
|
|
|
+ </template>
|
|
|
+ </UiCollection>
|
|
|
+
|
|
|
+ </template>
|
|
|
+
|
|
|
+
|
|
|
+Dans components/Ui/Collection.vue :
|
|
|
+
|
|
|
+ const { rootModel, rootId, model, query }: ToRefs = toRefs(props)
|
|
|
+ const { $dataProvider } = useContext()
|
|
|
+ const { getCollection } = useDataUtils($dataProvider)
|
|
|
+ const {fetchState} = getCollection(model.value, rootModel.value, rootId.value)
|
|
|
+ const items: ComputedRef<Collection> = computed(() => queryHelper.getCollection(query.value))
|
|
|
+
|
|
|
+ return {
|
|
|
+ items,
|
|
|
+ fetchState
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+Est-ce qu'on peut espérer quelque chose de ce genre ?
|
|
|
+
|
|
|
+ const { em } = useEntityManager()
|
|
|
+
|
|
|
+ const { fetchState, contactPoints } = em.fetchBy(ContactPoint, Organization, organization_id)
|
|
|
+
|
|
|
+ return {
|
|
|
+ contactPoints,
|
|
|
+ fetchState
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+##### 4- Formulaire de création / édition d'une entité
|
|
|
+
|
|
|
+Exemple de pages/organization/contact_points/_id.vue :
|
|
|
+
|
|
|
+ <script>
|
|
|
+ setup () {
|
|
|
+ const {$dataProvider, route} = useContext()
|
|
|
+ const {getItemToEdit} = useDataUtils($dataProvider)
|
|
|
+ const id = parseInt(route.value.params.id)
|
|
|
+ const {fetchState} = getItemToEdit(id, ContactPoint)
|
|
|
+ return {
|
|
|
+ id,
|
|
|
+ fetchState
|
|
|
+ }
|
|
|
+ </script>
|
|
|
+
|
|
|
+ <template>
|
|
|
+ <FormOrganizationContactPoint :id="id" v-if="!fetchState.pending"></FormOrganizationContactPoint>
|
|
|
+ </template>
|
|
|
+
|
|
|
+Dans components/Form/Organization/ContactPoint.vue :
|
|
|
+
|
|
|
+ <script>
|
|
|
+ setup () {
|
|
|
+ const repository: VuexRepository<Model> = repositoryHelper.getRepository(ContactPoint)
|
|
|
+ const query: Query = repository.query()
|
|
|
+
|
|
|
+ (...)
|
|
|
+
|
|
|
+ return {
|
|
|
+ model: ContactPoint,
|
|
|
+ query: () => query,
|
|
|
+ (...)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ </script>
|
|
|
+
|
|
|
+ <template>
|
|
|
+ <UiForm
|
|
|
+ :id="id"
|
|
|
+ :model="model"
|
|
|
+ :query="query()"
|
|
|
+ :submitActions="submitActions">
|
|
|
+ >
|
|
|
+ <template #form.input="{entry, updateRepository}">
|
|
|
+ (...)
|
|
|
+ </template>
|
|
|
+ </UiForm>
|
|
|
+ </template>
|
|
|
+
|
|
|
+Dans components/Ui/Form.vue :
|
|
|
+
|
|
|
+ <script>
|
|
|
+ setup () {
|
|
|
+ const {$dataPersister, store, app: {i18n}} = useContext()
|
|
|
+ const {id, query}: ToRefs = toRefs(props)
|
|
|
+
|
|
|
+ const entry: ComputedRef<AnyJson> = computed(() => {
|
|
|
+ return queryHelper.getFlattenEntry(query.value, id.value)
|
|
|
+ })
|
|
|
+
|
|
|
+ (...)
|
|
|
+
|
|
|
+ const submit = async (next: string|null = null) => {
|
|
|
+ if(await validate()){
|
|
|
+ markAsNotDirty()
|
|
|
+
|
|
|
+ try {
|
|
|
+ const response = await $dataPersister.invoke({
|
|
|
+ type: QUERY_TYPE.MODEL,
|
|
|
+ model: props.model,
|
|
|
+ id: store.state.form.formStatus === FORM_STATUS.EDIT ? id.value : null,
|
|
|
+ idTemp: store.state.form.formStatus === FORM_STATUS.CREATE ? id.value : null,
|
|
|
+ query: props.query
|
|
|
+ })
|
|
|
+
|
|
|
+ (...)
|
|
|
+ }
|
|
|
+
|
|
|
+ const quitForm = () => {
|
|
|
+ // reset entity
|
|
|
+ const entryCopy = query.value.first()
|
|
|
+ if (entryCopy && entryCopy.$getAttributes().originalState) {
|
|
|
+ repositoryHelper.persist(props.model, entryCopy.$getAttributes().originalState)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ submit,
|
|
|
+ updateRepository,
|
|
|
+ entry,
|
|
|
+ quitForm,
|
|
|
+ }
|
|
|
+ </script>
|
|
|
+
|
|
|
+ <template>
|
|
|
+ <v-form
|
|
|
+ ref="form"
|
|
|
+ lazy-validation
|
|
|
+ :readonly="readonly"
|
|
|
+ >
|
|
|
+ (...)
|
|
|
+ <UiButtonSubmit
|
|
|
+ v-if="!readonly"
|
|
|
+ @submit="submit"
|
|
|
+ :actions="actions"
|
|
|
+ ></UiButtonSubmit>
|
|
|
+ </v-form>
|
|
|
+ </template>
|
|
|
+
|
|
|
+
|
|
|
+Alternative :
|
|
|
+
|
|
|
+ (...)
|
|
|
+
|
|
|
+##### 5- Population d'un input par un enum
|
|
|
+
|
|
|
+Exemple sur la page components/Form/Organization/ContactPoint.vue :
|
|
|
+
|
|
|
+ <UiInputEnum
|
|
|
+ field="contactType"
|
|
|
+ label="contactpoint_type"
|
|
|
+ :data="entry['contactType']"
|
|
|
+ enum-type="contact_point_type"
|
|
|
+ @update="updateRepository"
|
|
|
+ />
|
|
|
+
|
|
|
+Dans components/Ui/Input/Enum.vue :
|
|
|
+
|
|
|
+ const { enumType } = props
|
|
|
+ const { $dataProvider, store } = useContext()
|
|
|
+ (...)
|
|
|
+
|
|
|
+ const items: Ref<Array<EnumChoices>> = ref([])
|
|
|
+ useFetch(async () => {
|
|
|
+ items.value = await $dataProvider.invoke({
|
|
|
+ type: QUERY_TYPE.ENUM,
|
|
|
+ enumType
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ return {
|
|
|
+ items,
|
|
|
+ (...)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+Alternative :
|
|
|
+
|
|
|
+ (...)
|
|
|
+
|
|
|
+
|
|
|
+##### 6- Population d'un input par des entités (ex: liste des pays)
|
|
|
+
|
|
|
+Exemple sur la page components/Form/Organization/Address.vue :
|
|
|
+
|
|
|
+ <script>
|
|
|
+
|
|
|
+ const {countries, fetchState: countriesFetchingState} = useCountryProvider($dataProvider)
|
|
|
+
|
|
|
+ return {
|
|
|
+ (...)
|
|
|
+ countries,
|
|
|
+ countriesFetchingState,
|
|
|
+ (...)
|
|
|
+ }
|
|
|
+ </script>
|
|
|
+
|
|
|
+ <template>
|
|
|
+ <UiInputAutocomplete
|
|
|
+ field="addressPostal.addressCountry"
|
|
|
+ label="addressCountry"
|
|
|
+ :data="getIdFromUri(entry['addressPostal.addressCountry'])"
|
|
|
+ :items="countries"
|
|
|
+ :isLoading="countriesFetchingState.pending"
|
|
|
+ :item-text="['name']"
|
|
|
+ @update="updateRepository(`/api/countries/${$event}`, 'addressPostal.addressCountry')"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+
|
|
|
+Dans composables/data/useCountryProvider.ts :
|
|
|
+
|
|
|
+ export function useCountryProvider($dataprovider: DataProvider){
|
|
|
+ const {fetch, fetchState} = useFetch(async () => {
|
|
|
+ await $dataprovider.invoke({
|
|
|
+ type: QUERY_TYPE.MODEL,
|
|
|
+ model: Country
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ const countries = computed(() => {
|
|
|
+ return repositoryHelper.findCollectionFromModel(Country)
|
|
|
+ })
|
|
|
+
|
|
|
+ return {
|
|
|
+ countries,
|
|
|
+ fetch,
|
|
|
+ fetchState
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+Dans services/store/repository.ts :
|
|
|
+
|
|
|
+ public findCollectionFromModel (model: typeof Model, orderBy?: OrderByVuexOrm): Collection {
|
|
|
+ const repository = this.getRepository(model)
|
|
|
+ if(orderBy){
|
|
|
+ for(const orderKey in orderBy){
|
|
|
+ repository.orderBy(orderKey, orderBy[orderKey])
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return repository.all()
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+Alternative :
|
|
|
+
|
|
|
+ (...)
|
|
|
+
|
|
|
+
|
|
|
+##### 7- Population d'un input depuis une source externe (ex : adresses)
|
|
|
+
|
|
|
+Exemple sur la page components/Form/Organization/Address.vue :
|
|
|
+
|
|
|
+ <script>
|
|
|
+ const {searchFunction: addressSearch, updateCpAddress} = useAddressPostalUtils($dataProvider)
|
|
|
+
|
|
|
+ return {
|
|
|
+ (...)
|
|
|
+ addressSearch,
|
|
|
+ updateCpAddress,
|
|
|
+ (...)
|
|
|
+ }
|
|
|
+ </script
|
|
|
+
|
|
|
+ <template>
|
|
|
+ (...)
|
|
|
+
|
|
|
+ <UiInputAutocompleteWithAPI
|
|
|
+ field="owner"
|
|
|
+ label="importAddress"
|
|
|
+ :item-text="['person.givenName', 'person.name']"
|
|
|
+ :searchFunction="accessSearch"
|
|
|
+ @update="updateAccessAddress"
|
|
|
+ />
|
|
|
+
|
|
|
+ (...)
|
|
|
+
|
|
|
+ <UiInputAutocompleteWithAPI
|
|
|
+ field="addressPostal.postalCode"
|
|
|
+ label="postalCode"
|
|
|
+ :data="getAutoCompleteAddressItem"
|
|
|
+ :item-text="['postcode']"
|
|
|
+ :slotText="['postcode', 'city']"
|
|
|
+ :searchFunction="addressSearch"
|
|
|
+ :returnObject="true"
|
|
|
+ @update="updateCpAddress($event, updateRepository)"
|
|
|
+ />
|
|
|
+
|
|
|
+ <UiInputAutocompleteWithAPI
|
|
|
+ field="addressPostal.addressCity"
|
|
|
+ label="addressCity"
|
|
|
+ :data="getAutoCompleteAddressItem"
|
|
|
+ :item-text="['city']"
|
|
|
+ :slotText="['postcode', 'city']"
|
|
|
+ :searchFunction="addressSearch"
|
|
|
+ :returnObject="true"
|
|
|
+ @update="updateCpAddress($event, updateRepository)"
|
|
|
+ />
|
|
|
+
|
|
|
+ (...)
|
|
|
+ </template>
|
|
|
+
|
|
|
+Dans components/Ui/Input/AutocompleteWithAPI.vue :
|
|
|
+
|
|
|
+
|
|
|
+ useFetch(async () => {
|
|
|
+ isLoading.value = true
|
|
|
+ const r = await $dataProvider.invoke({
|
|
|
+ type: QUERY_TYPE.DEFAULT,
|
|
|
+ url: props.remoteUrl,
|
|
|
+ listArgs: {
|
|
|
+ filters:[
|
|
|
+ {key: 'id', value: ids.join(',')}
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ })
|
|
|
+ isLoading.value = false
|
|
|
+ remoteData.value = r.data
|
|
|
+ items.value = r.data
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
+Dans composables/data/useAddressPostalUtils.ts :
|
|
|
+
|
|
|
+ async function searchFunction(research: string, field: string): Promise<Array<AnyJson>> {
|
|
|
+ if (research) {
|
|
|
+ const response = await $dataProvider.invoke({
|
|
|
+ type: QUERY_TYPE.DEFAULT,
|
|
|
+ url: `https://api-adresse.data.gouv.fr/search/?q=${research}&type=municipality&autocomplete=1&limit=20`,
|
|
|
+ params: {
|
|
|
+ noXaccessId: true
|
|
|
+ }
|
|
|
+ })
|
|
|
+ const apiResponse = response.data.features.map((data: AnyJson) => data.properties)
|
|
|
+
|
|
|
+ (...)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+Alternative :
|
|
|
+
|
|
|
+ (...)
|
|
|
+
|
|
|
+
|
|
|
+##### 8- Affichage / upload d'une image
|
|
|
+
|
|
|
+Sur la page pages/organization/index.vue :
|
|
|
+
|
|
|
+ <UiImage
|
|
|
+ :id="getIdFromUri(entry['logo'])"
|
|
|
+ :upload="true"
|
|
|
+ :width="200"
|
|
|
+ field="logo"
|
|
|
+ :ownerId="id"
|
|
|
+ @update="updateRepository"
|
|
|
+ ></UiImage>
|
|
|
+
|
|
|
+Dans components/Ui/Image.vue :
|
|
|
+
|
|
|
+ <script>
|
|
|
+ const {getOne, provideImg} = useImageProvider($dataProvider, $config)
|
|
|
+
|
|
|
+ const { imageLoaded, fetch } = getOne(props.id, props.imageByDefault, props.height, props.width)
|
|
|
+ </script>
|
|
|
+
|
|
|
+ <template>
|
|
|
+ <v-img
|
|
|
+ :src="imgSrcReload ? imgSrcReload : imageLoaded"
|
|
|
+ :lazy-src="require(`/assets/images/byDefault/${imageByDefault}`)"
|
|
|
+ :height="height"
|
|
|
+ :width="width"
|
|
|
+ aspect-ratio="1"
|
|
|
+ >(...)</v-img>
|
|
|
+
|
|
|
+ <UiInputImage
|
|
|
+ v-if="openUpload"
|
|
|
+ @close="openUpload=false"
|
|
|
+ :existingImageId="id"
|
|
|
+ :field="field"
|
|
|
+ :ownerId="ownerId"
|
|
|
+ @update="$emit('update', $event, field); openUpload=false"
|
|
|
+ @reload="fetch();openUpload=false"
|
|
|
+ @reset="reset"
|
|
|
+ ></UiInputImage>
|
|
|
+ </template>
|
|
|
+
|
|
|
+Dans components/Ui/Input/Image.vue :
|
|
|
+
|
|
|
+ const {$dataProvider, $config, $dataPersister} = useContext()
|
|
|
+ const {getOne} = useImageProvider($dataProvider, $config)
|
|
|
+
|
|
|
+ const fileToSave = new File()
|
|
|
+ const cropper:Ref<any> = ref(null)
|
|
|
+ const image: Ref<AnyJson> = ref({
|
|
|
+ id: null,
|
|
|
+ src: null,
|
|
|
+ file: null,
|
|
|
+ name: null
|
|
|
+ })
|
|
|
+
|
|
|
+ (...)
|
|
|
+
|
|
|
+ if(props.existingImageId){
|
|
|
+ useFetch(async () => {
|
|
|
+ const result: ApiResponse = await $dataProvider.invoke({
|
|
|
+ type: QUERY_TYPE.DEFAULT,
|
|
|
+ url: 'api/files',
|
|
|
+ id: props.existingImageId
|
|
|
+ })
|
|
|
+
|
|
|
+ const config = JSON.parse(result.data.config)
|
|
|
+ (...)
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ const { fetchState, imageLoaded } = getOne(props.existingImageId)
|
|
|
+ const unwatch: WatchStopHandle = watch(imageLoaded, (newValue, oldValue) => {
|
|
|
+ if (newValue === oldValue || typeof newValue === 'undefined') { return }
|
|
|
+ image.value.src = newValue
|
|
|
+ })
|
|
|
+
|
|
|
+ const save = async () => {
|
|
|
+ fileToSave.config = JSON.stringify({
|
|
|
+ x: coordinates.value.left,
|
|
|
+ y: coordinates.value.top,
|
|
|
+ height: coordinates.value.height,
|
|
|
+ width: coordinates.value.width
|
|
|
+ })
|
|
|
+
|
|
|
+ //Cas d'un PUT : l'image existe déjà on bouge simplement le cropper
|
|
|
+ if(image.value.id){
|
|
|
+ fileToSave.id = image.value.id
|
|
|
+ repositoryHelper.persist(File, fileToSave)
|
|
|
+ await $dataPersister.invoke({
|
|
|
+ type: QUERY_TYPE.MODEL,
|
|
|
+ model: File,
|
|
|
+ id: fileToSave.id
|
|
|
+ })
|
|
|
+ //On émet un évent afin de mettre à jour le formulaire de départ
|
|
|
+ emit('reload')
|
|
|
+ }
|
|
|
+
|
|
|
+ //Post : on créer une nouvelle image donc on passe par l'api legacy...
|
|
|
+ else{
|
|
|
+ if(image.value.file){
|
|
|
+ //On créer l'objet File à sauvegarder
|
|
|
+ fileToSave.name = image.value.name
|
|
|
+ fileToSave.imgFieldName = props.field
|
|
|
+ fileToSave.visibility = 'EVERYBODY'
|
|
|
+ fileToSave.folder = 'IMAGES'
|
|
|
+
|
|
|
+ if(props.ownerId)
|
|
|
+ fileToSave.ownerId = props.ownerId
|
|
|
+
|
|
|
+ //Appel au datapersister
|
|
|
+ const response: ApiResponse = await $dataPersister.invoke({
|
|
|
+ type: QUERY_TYPE.FILE,
|
|
|
+ baseUrl: $config.baseURL_Legacy,
|
|
|
+ data: fileToSave.$toJson(),
|
|
|
+ file: image.value.file
|
|
|
+ })
|
|
|
+ //On émet un évent afin de mettre à jour le formulaire de départ
|
|
|
+ emit('update', response.data['@id'])
|
|
|
+ }else{
|
|
|
+ //On reset l'image : on a appuyer sur "poubelle" puis on enregistre
|
|
|
+ emit('reset')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+Dans composables/data/useImageProvider.ts :
|
|
|
+
|
|
|
+ async function provideImg(id: number, height: number = 0, width: number = 0) {
|
|
|
+ return await $dataProvider.invoke({
|
|
|
+ type: QUERY_TYPE.IMAGE,
|
|
|
+ baseUrl: $config.baseURL_Legacy,
|
|
|
+ imgArgs: {
|
|
|
+ id: id,
|
|
|
+ height: height,
|
|
|
+ width: width
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+Alternative :
|
|
|
+
|
|
|
+ (...)
|
|
|
+
|
|
|
+
|
|
|
+##### 9. Téléchargement / upload de fichier
|
|
|
+
|
|
|
+_(exemple?)_
|
|
|
+
|
|
|
+
|
|
|
+##### 10- Affichage et éditions des notifications
|
|
|
+
|
|
|
+Dans components/Layout/Header/Notification.vue :
|
|
|
+
|
|
|
+ const {fetch, fetchState} = useFetch(async () => {
|
|
|
+ data.value = await $dataProvider.invoke({
|
|
|
+ type: QUERY_TYPE.MODEL,
|
|
|
+ model: Notification,
|
|
|
+ listArgs: {
|
|
|
+ itemsPerPage: 10,
|
|
|
+ page: page.value
|
|
|
+ }
|
|
|
+ })
|
|
|
+ loading.value = false
|
|
|
+ })
|
|
|
+
|
|
|
+ const notifications: ComputedRef = computed(() => {
|
|
|
+ const query = repositoryHelper.getRepository(Notification).with('message').orderBy('id', 'desc')
|
|
|
+ return queryHelper.getCollection(query)
|
|
|
+ })
|
|
|
+
|
|
|
+ (...)
|
|
|
+
|
|
|
+ const markNotificationsAsRead = () => {
|
|
|
+ unreadNotification.value.map((notification:Notification)=>{
|
|
|
+ notification.notificationUsers = ['read']
|
|
|
+ repositoryHelper.persist(Notification, notification)
|
|
|
+ createNewNotificationUsers(notification)
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ const createNewNotificationUsers = (notification: Notification) =>{
|
|
|
+ const newNotificationUsers = repositoryHelper.persist(NotificationUsers, new NotificationUsers(
|
|
|
+ {
|
|
|
+ access:`/api/accesses/${currentAccessId}`,
|
|
|
+ notification:`/api/notifications/${notification.id}`,
|
|
|
+ isRead: true
|
|
|
+ }
|
|
|
+ )) as NotificationUsers
|
|
|
+
|
|
|
+ $dataPersister.invoke({
|
|
|
+ type: QUERY_TYPE.MODEL,
|
|
|
+ model: NotificationUsers,
|
|
|
+ idTemp: newNotificationUsers.id,
|
|
|
+ showProgress: false
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+Alternative :
|
|
|
+
|
|
|
+ (...)
|
|
|
+
|
|
|
+##### 11- Validation de données
|
|
|
+
|
|
|
+Sur la page pages/organization/index.vue :
|
|
|
+
|
|
|
+ const checkSiretHook = async (siret: string, field: string, updateRepository: any) => {
|
|
|
+ await checkSiret(siret)
|
|
|
+ if (!siretError.value) { updateRepository(siret, field) }
|
|
|
+ }
|
|
|
+
|
|
|
+Dans composables/form/useValidator.ts :
|
|
|
+
|
|
|
+ function useHandleSiret() {
|
|
|
+ const siretError: Ref<boolean> = ref(false)
|
|
|
+ const siretErrorMessage: Ref<string> = ref('')
|
|
|
+
|
|
|
+ const checkSiret = async (siret: string) => {
|
|
|
+ const response = await $dataProvider.invoke({
|
|
|
+ type: QUERY_TYPE.DEFAULT,
|
|
|
+ url: '/api/siret-checking',
|
|
|
+ id: siret
|
|
|
+ })
|
|
|
+
|
|
|
+ if (typeof response !== 'undefined') {
|
|
|
+ siretError.value = !response.isCorrect
|
|
|
+ siretErrorMessage.value = response.isCorrect ? '' : i18n.t('siret_error') as string
|
|
|
+ } else {
|
|
|
+ siretError.value = false
|
|
|
+ siretErrorMessage.value = ''
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ siretError,
|
|
|
+ siretErrorMessage,
|
|
|
+ checkSiret
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+Alternative :
|
|
|
+
|
|
|
+ (...)
|
|
|
+
|
|
|
+
|
|
|
+##### 12- Affichage de données issues d'une api externe ou de routes custom
|
|
|
+
|
|
|
+Dans components/Ui/Template/MobytStatus.vue :
|
|
|
+
|
|
|
+ const mobytStatus: Ref<MobytUserStatus | null> = ref(null)
|
|
|
+
|
|
|
+ // fetch the mobyt status
|
|
|
+ const { fetchState } = useFetch(async () => {
|
|
|
+ try {
|
|
|
+ const response:ApiResponse = await $dataProvider.invoke({
|
|
|
+ type: QUERY_TYPE.DEFAULT,
|
|
|
+ url: '/api/mobyt/status/' + id
|
|
|
+ })
|
|
|
+ mobytStatus.value = response.data as MobytUserStatus
|
|
|
+ if(!mobytStatus.value?.active) emit('disabled_sms_row')
|
|
|
+ } catch (Error) {
|
|
|
+ // eslint-disable-next-line no-console
|
|
|
+ console.error('Error: Mobyt status not found')
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+Même remarque que pour le 1-, ce serait mieux d'utiliser directement le service Connection :
|
|
|
+
|
|
|
+ async getUserProfile ({ dispatch }) {
|
|
|
+ const myProfile = await this.app.context.$connection.get('/api/my_profile')
|
|
|
+ await dispatch('profile/access/setProfile', myProfile)
|
|
|
+ }
|
|
|
+
|
|
|
+ // fetch the mobyt status
|
|
|
+ const { fetchState } = useFetch(async () => {
|
|
|
+ try {
|
|
|
+ const response: ApiResponse = await $connection.get('/api/mobyt/status/' + id)
|
|
|
+ mobytStatus.value = response as MobytUserStatus
|
|
|
+ if(!mobytStatus.value?.active) emit('disabled_sms_row')
|
|
|
+ } catch (Error) {
|
|
|
+ // eslint-disable-next-line no-console
|
|
|
+ console.error('Error: Mobyt status not found')
|
|
|
+ }
|
|
|
+ })
|