@saooti/octopus-sdk 41.0.17 → 41.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/CHANGELOG.md +30 -1
  2. package/index.ts +4 -0
  3. package/package.json +1 -1
  4. package/src/components/composable/route/types.ts +47 -0
  5. package/src/components/composable/route/useAdvancedParamInit.ts +29 -4
  6. package/src/components/composable/route/useRouteUpdateParams.ts +9 -19
  7. package/src/components/composable/route/useSimplePageParam.ts +6 -4
  8. package/src/components/display/emission/EmissionItem.vue +17 -6
  9. package/src/components/display/emission/EmissionList.vue +13 -1
  10. package/src/components/display/filter/AdvancedSearch.vue +237 -170
  11. package/src/components/display/podcasts/PodcastList.vue +4 -1
  12. package/src/components/display/podcasts/PodcastModuleBox.vue +23 -6
  13. package/src/components/display/podcasts/TagList.vue +2 -2
  14. package/src/components/form/ClassicCheckbox.vue +9 -0
  15. package/src/components/form/ClassicMultiselect.vue +1 -0
  16. package/src/components/form/ClassicTagInput.vue +155 -0
  17. package/src/components/misc/ClassicAlert.vue +9 -1
  18. package/src/components/misc/ClassicHelpButton.vue +3 -0
  19. package/src/components/misc/ClassicImageBanner.vue +33 -0
  20. package/src/components/misc/ErrorMessage.vue +4 -2
  21. package/src/components/pages/EmissionPage.vue +32 -1
  22. package/src/components/pages/EmissionsPage.vue +66 -61
  23. package/src/components/pages/PodcastsPage.vue +71 -66
  24. package/src/locale/de.ts +3 -0
  25. package/src/locale/en.ts +3 -0
  26. package/src/locale/es.ts +3 -0
  27. package/src/locale/fr.ts +3 -0
  28. package/src/locale/it.ts +3 -0
  29. package/src/locale/sl.ts +3 -0
  30. package/src/router/router.ts +4 -0
  31. package/src/stores/class/general/emission.ts +8 -0
  32. package/src/stores/class/general/podcast.ts +2 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 41.0.19 (13/11/2025)
4
+
5
+ **Features**
6
+
7
+ - Ajout recherche par référence ayant-droit sur les émissions et épisodes
8
+ - Ajout du composant `ClassicTagInput` pour simplifier la saisie de tags
9
+ - Affichage des mots-clés lors de la consultation d'une émission
10
+
11
+ **Misc**
12
+
13
+ - Amélioration affichage des crédits dans les épisodes
14
+
15
+ ## 41.0.18 (12/11/2025)
16
+
17
+ **Features**
18
+
19
+ - Changements pour les émissions non publiées (`visible = false`) :
20
+ - La recherche permet de les afficher quand on affiche les épisodes non
21
+ publiés
22
+ - Un bandeau s'affiche pour indiquer que l'émission n'est pas disponible aux
23
+ auditeurs
24
+
25
+ **Misc**
26
+
27
+ - Ajout d'une propriété `relative` pour faire fonctionner les
28
+ `ClassicHelpButton` quand un parent a une position relative.
29
+ - Correction alignement du texte dans `ClassicAlert`
30
+ - Ajout d'un slot `after-label` sur `ClassicCheckbox`
31
+
3
32
  ## 41.0.17 (07/11/2025)
4
33
 
5
34
  **Features**
@@ -20,4 +49,4 @@
20
49
 
21
50
  - Bannière 'en cours de traitement' ne s'affiche plus dans les listes
22
51
  - Ajustements sur `ClassicSelect` & `ClassicHelpButton`
23
- - Ajout de ClassicAlert, pour l'affichage de message
52
+ - Ajout de `ClassicAlert`, pour l'affichage de message
package/index.ts CHANGED
@@ -98,6 +98,7 @@ export const getClassicEmojiPicker = () => import("./src/components/form/Classic
98
98
  export const getClassicContentEditable = () => import("./src/components/form/ClassicContentEditable.vue");
99
99
  export const getSwiperList = () => import("./src/components/display/list/SwiperList.vue");
100
100
  export const getClassicCopyButton = () => import("./src/components/form/ClassicCopyButton.vue");
101
+ export const getClassicTagInput = () => import("./src/components/form/ClassicTagInput.vue");
101
102
 
102
103
 
103
104
  //Composable
@@ -156,6 +157,8 @@ import { setupRouter } from './src/router/utils';
156
157
  // Types
157
158
  import { type SelectOption } from "./src/components/form/ClassicSelect.vue";
158
159
 
160
+ import { ROUTE_PARAMS } from "./src/components/composable/route/types";
161
+
159
162
  export {
160
163
  useResizePhone,
161
164
  useTagOf,
@@ -189,4 +192,5 @@ export {
189
192
  displayHelper,
190
193
  setupRouter,
191
194
  SelectOption,
195
+ ROUTE_PARAMS
192
196
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saooti/octopus-sdk",
3
- "version": "41.0.17",
3
+ "version": "41.0.19",
4
4
  "private": false,
5
5
  "description": "Javascript SDK for using octopus",
6
6
  "author": "Saooti",
@@ -0,0 +1,47 @@
1
+ export interface RouteProps {
2
+ pr?: number;
3
+ ps?: number;
4
+ routeQuery?: string;
5
+ routeMonetisable?: string;
6
+ routeIab?: number;
7
+ routeSort?: string;
8
+ routeIncludeHidden?: string;
9
+ routeFrom?: string;
10
+ routeTo?: string;
11
+ routeValidity?: string;
12
+ routeOnlyVideo?: string;
13
+ routeOrga?: string;
14
+ routeRubriques?: string;
15
+ /** The filter on beneficiaries defined on the route props */
16
+ routeBeneficiaries?: string[];
17
+ }
18
+
19
+ type DateStr = string;
20
+
21
+ export interface RouteParams {
22
+ /** The organisation for which we display the emissions/episodes */
23
+ productor?: string;
24
+ }
25
+
26
+ export interface AdvancedRouteParams extends RouteParams {
27
+ /** If true, only show episodes with video */
28
+ v?: 'true';
29
+ /** When set, display data from this date */
30
+ from?: DateStr;
31
+ /** When set, display data up to this date */
32
+ to?: DateStr;
33
+ /** When set, filter on beneficiaries */
34
+ b?: string[];
35
+ q?: string;
36
+ }
37
+
38
+ type RouteParamEnum =
39
+ 'Beneficiaries' |
40
+ 'Query'
41
+ ;
42
+
43
+ /** Utility to access route params by constants instead of undefined value */
44
+ export const ROUTE_PARAMS: Record<RouteParamEnum, keyof AdvancedRouteParams> = {
45
+ Beneficiaries: 'b',
46
+ Query: 'q'
47
+ };
@@ -7,7 +7,9 @@ import { useRubriquesFilterParam } from './useRubriquesFilterParam';
7
7
  import { computed, nextTick, onMounted, Ref, ref, watch } from "vue";
8
8
  import dayjs from "dayjs";
9
9
 
10
- export const useAdvancedParamInit = (props: any, isEmission: boolean)=>{
10
+ import { RouteProps } from "./types";
11
+
12
+ export const useAdvancedParamInit = (props: RouteProps, isEmission: boolean) => {
11
13
 
12
14
  const { searchPattern,organisationId, searchMinSize, paginateFirst, initSearchPattern, initOrga} = useSimplePageParam(props, false, true);
13
15
  const { isEditRights, isPodcastmaker } = useOrgaComputed();
@@ -26,6 +28,7 @@ export const useAdvancedParamInit = (props: any, isEmission: boolean)=>{
26
28
  const validity = ref("true");
27
29
  const iabId: Ref<number|undefined> = ref(undefined);
28
30
  const rubriqueFilter: Ref<Array<RubriquageFilter>> = ref([]);
31
+ const beneficiaries = ref<string[]|null>(null);
29
32
 
30
33
 
31
34
  const organisationRight = computed(() => isEditRights(organisationId.value));
@@ -60,6 +63,7 @@ export const useAdvancedParamInit = (props: any, isEmission: boolean)=>{
60
63
  watch(() => props.routeIab, () => {iabId.value = props.routeIab;});
61
64
  watch(() => props.routeOrga, () => initOrga());
62
65
  watch(() => props.routeRubriques, () => initRubriquageFilter());
66
+ watch(() => props.routeBeneficiaries, initBeneficiariesFilter);
63
67
  watch(organisationId, () => {
64
68
  if (!isInit.value) {
65
69
  return;
@@ -146,7 +150,27 @@ export const useAdvancedParamInit = (props: any, isEmission: boolean)=>{
146
150
  rubriqueFilter.value = rubriqueFilterToUpdate;
147
151
  }
148
152
 
149
- return {
153
+ function initBeneficiariesFilter() {
154
+ const data = props.routeBeneficiaries as string[];
155
+ // No beneficiaries
156
+ if (
157
+ data === undefined ||
158
+ data === null ||
159
+ data.length === 0
160
+ ) {
161
+ beneficiaries.value = null;
162
+ return;
163
+ }
164
+
165
+ // No changes
166
+ if(beneficiaries.value && data === beneficiaries.value){
167
+ return;
168
+ }
169
+
170
+ beneficiaries.value = data;
171
+ }
172
+
173
+ return {
150
174
  organisationId,
151
175
  searchPattern,
152
176
  monetisable,
@@ -160,6 +184,7 @@ export const useAdvancedParamInit = (props: any, isEmission: boolean)=>{
160
184
  paginateFirst,
161
185
  validity,
162
186
  rubriquesFilterArrayIds,
163
- isInit
164
- }
187
+ isInit,
188
+ beneficiaries
189
+ };
165
190
  }
@@ -1,8 +1,6 @@
1
1
  import { useRoute, useRouter } from 'vue-router';
2
2
 
3
- interface RouteParams {
4
- productor: string;
5
- }
3
+ import { RouteParams, AdvancedRouteParams } from './types';
6
4
 
7
5
  export const useRouteUpdateParams = () => {
8
6
 
@@ -17,40 +15,32 @@ export const useRouteUpdateParams = () => {
17
15
  return ['podcasts', 'emissions'].includes(route.name?.toString()??"");
18
16
  }
19
17
 
20
- function updatePaginateSize(ps:number, force= false){
18
+ function updatePaginateSize(ps:number, force = false): void{
21
19
  if(force ||checkPage()){
22
20
  router.push({query: {...route.query, ...{ps:ps, pr:1}}});
23
21
  }
24
22
  }
25
23
 
26
- function updateRouteParam(update: {[key:string]: string|undefined}, force= false){
24
+ function updateRouteParam(update: RouteParams, force = false): void {
27
25
  if(force || checkPage()){
28
26
  router.push({query: {...route.query, ...update}});
29
27
  }
30
28
  }
31
29
 
32
- function updateRouteParamAdvanced(update: {[key:string]: string|undefined}){
30
+ function updateRouteParamAdvanced(update: AdvancedRouteParams): void {
33
31
  if(checkPageAdvanced()){
34
32
  router.push({query: {...route.query, ...update}});
35
33
  }
36
34
  }
37
35
 
38
- function updateFiltersParam(update: {[key:string]: string|undefined}, advancedUpdate: {[key:string]: string|undefined}){
39
- if(checkPageAdvanced()){
40
- router.push({query: {...route.query, ...update, ...advancedUpdate}});
41
- }else{
42
- router.push({query: {...route.query, ...update}});
36
+ function updateFiltersParam(update: RouteParams, advancedUpdate: AdvancedRouteParams){
37
+ if(checkPageAdvanced()) {
38
+ router.push({query: { ...route.query, ...update, ...advancedUpdate }});
39
+ } else {
40
+ router.push({query: { ...route.query, ...update }});
43
41
  }
44
42
  }
45
43
 
46
- /*
47
- function updateRouteParams(params: Partial<RouteParams>) {
48
- router.push({ query: {
49
- ...route.query,
50
- ...params
51
- }});
52
- }*/
53
-
54
44
  return {
55
45
  updatePaginateSize,
56
46
  updateRouteParam,
@@ -2,7 +2,9 @@ import { useFilterStore } from '../../../stores/FilterStore';
2
2
  import { useRouteUpdateParams } from './useRouteUpdateParams';
3
3
  import { computed, onMounted, Ref, ref, watch } from "vue";
4
4
 
5
- export const useSimplePageParam = (props: {readonly [key:string]: string|number}, force=false, advancedSearch=false)=>{
5
+ import { RouteProps, ROUTE_PARAMS } from "./types";
6
+
7
+ export const useSimplePageParam = (props: RouteProps, force=false, advancedSearch=false)=>{
6
8
 
7
9
  const { updateRouteParam } = useRouteUpdateParams();
8
10
 
@@ -24,7 +26,7 @@ export const useSimplePageParam = (props: {readonly [key:string]: string|number}
24
26
  if(!advancedSearch){
25
27
  const query = getMinSize(searchPattern.value);
26
28
  updateRouteParam({
27
- q: query.length ? query : undefined,
29
+ [ROUTE_PARAMS.Query]: query.length ? query : undefined,
28
30
  }, force);
29
31
  }
30
32
  });
@@ -51,7 +53,7 @@ export const useSimplePageParam = (props: {readonly [key:string]: string|number}
51
53
  }
52
54
 
53
55
 
54
- return {
56
+ return {
55
57
  searchPattern,
56
58
  organisationId,
57
59
  searchMinSize,
@@ -60,5 +62,5 @@ export const useSimplePageParam = (props: {readonly [key:string]: string|number}
60
62
  initOrga,
61
63
  updateRouteParam,
62
64
  isInit
63
- }
65
+ };
64
66
  }
@@ -16,7 +16,11 @@
16
16
  aria-hidden="true"
17
17
  alt=""
18
18
  :title="t('Emission name image', { name: emission.name })"
19
- />
19
+ >
20
+ <ClassicImageBanner v-if="!emissionVisible">
21
+ {{ t('Emission - Not available for listeners') }}
22
+ </ClassicImageBanner>
23
+
20
24
  <div class="classic-element-text">
21
25
  <div class="d-flex align-items-center element-name basic-line-clamp">
22
26
  <AlertIcon
@@ -63,12 +67,15 @@ import displayHelper from "../../../helper/displayHelper";
63
67
  import { computed, onBeforeMount, onMounted, ref, useTemplateRef } from "vue";
64
68
  import { Podcast } from "@/stores/class/general/podcast";
65
69
  import { ListClassicReturn } from "@/stores/class/general/listReturn";
70
+
71
+ import ClassicImageBanner from '../../misc/ClassicImageBanner.vue';
72
+
66
73
  import { useI18n } from "vue-i18n";
67
74
 
68
75
  //Props
69
76
  const props = defineProps({
70
77
  emission: { default: () => ({}), type: Object as () => Emission },
71
- })
78
+ });
72
79
 
73
80
  //Data
74
81
  const activeEmission = ref(true);
@@ -80,12 +87,16 @@ const { isPodcastmaker, isEditRights } = useOrgaComputed();
80
87
 
81
88
  //Computed
82
89
  const editRight = computed(() => isEditRights(props.emission.orga.id));
83
-
90
+ const emissionVisible = computed(() => {
91
+ return props.emission.visible !== false;
92
+ });
84
93
 
85
94
  onBeforeMount(()=>{
86
- if (!editRight.value) return;
95
+ if (!editRight.value) {
96
+ return;
97
+ }
87
98
  hasPodcast();
88
- })
99
+ });
89
100
 
90
101
  onMounted(()=>{
91
102
  const emissionDesc = useTemplateRef('descriptionEmission')?.value as HTMLElement;
@@ -119,4 +130,4 @@ async function hasPodcast(): Promise<void> {
119
130
  activeEmission.value = false;
120
131
  }
121
132
  }
122
- </script>
133
+ </script>
@@ -93,6 +93,8 @@ const props = defineProps({
93
93
  rubriquageId: { default: () => [], type: Array as () => Array<number> },
94
94
  noRubriquageId: { default: () => [], type: Array as () => Array<number> },
95
95
  nbPodcasts: { default: undefined, type: Number },
96
+ /** The beneficiaries to filter on */
97
+ beneficiaries: { default: null, type: Array as () => Array<string> }
96
98
  })
97
99
 
98
100
  //Data
@@ -125,7 +127,8 @@ const changePaginate = computed(() => `${props.first}|${props.size}`);
125
127
  /** Computed property to track for configuration changes */
126
128
  const changed = computed(() => {
127
129
  return `${props.organisationId}|${props.query}|${props.monetisable}|${props.includeHidden}|\
128
- ${props.iabId}|${props.rubriqueId}|${props.rubriquageId}|${props.before}|${props.after}|${props.sort}|${props.noRubriquageId}`;
130
+ ${props.iabId}|${props.rubriqueId}|${props.rubriquageId}|${props.before}|\
131
+ ${props.after}|${props.sort}|${props.noRubriquageId}|${props.beneficiaries}`;
129
132
  });
130
133
  const sortText = computed(() => {
131
134
  let textSort = "";
@@ -191,7 +194,16 @@ async function fetchContent(reset: boolean): Promise<void> {
191
194
  rubriqueId: props.rubriqueId.length ? props.rubriqueId : undefined,
192
195
  rubriquageId: props.rubriquageId.length ? props.rubriquageId : undefined,
193
196
  includeHidden: props.includeHidden,
197
+ beneficiary: props.beneficiaries ?? undefined
194
198
  };
199
+
200
+ // When fetching hidden episodes, also fetch hidden emissions
201
+ if (props.includeHidden === true) {
202
+ param.visible = 'ALL';
203
+ } else {
204
+ param.visible = 'VISIBLE';
205
+ }
206
+
195
207
  try {
196
208
  const data = await classicApi.fetchData<ListClassicReturn<Emission>>({
197
209
  api: 0,