@saooti/octopus-sdk 41.12.0-beta3 → 41.12.0
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.
- package/CHANGELOG.md +5 -1
- package/index.ts +1 -1
- package/package.json +1 -1
- package/src/api/index.ts +1 -0
- package/src/api/radioApi.ts +18 -2
- package/src/api/rubriquesApi.ts +68 -0
- package/src/components/composable/usePresentationItem.ts +78 -0
- package/src/components/display/emission/EmissionInlineList.vue +1 -1
- package/src/components/display/emission/EmissionPresentationItem.vue +25 -16
- package/src/components/display/podcastmaker/PodcastmakerHeader.vue +60 -45
- package/src/components/display/podcasts/PodcastPresentationList.vue +103 -89
- package/src/components/form/ClassicButtonGroup.vue +12 -6
- package/src/components/layouts/PresentationItem.vue +149 -104
- package/src/stores/CacheStore.ts +17 -11
- package/src/stores/ParamSdkStore.ts +22 -0
- package/src/stores/class/general/organisation.ts +7 -3
- package/src/stores/class/radio/canal.ts +30 -8
- package/src/stores/class/radio/recurrence.ts +6 -5
- package/tests/components/composable/usePresentationItem.spec.ts +163 -0
- package/tests/components/display/emission/EmissionPresentationItem.spec.ts +45 -0
- package/tests/components/display/podcasts/PodcastPresentationList.spec.ts +107 -0
- package/tests/components/form/ClassicButtonGroup.spec.ts +26 -0
- package/tests/components/layouts/PresentationItem.spec.ts +36 -0
- package/tests/stores/CacheStore.spec.ts +109 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
-
## 41.12.0 (
|
|
3
|
+
## 41.12.0 (13/07/2026)
|
|
4
4
|
|
|
5
5
|
**Features**
|
|
6
6
|
|
|
@@ -21,11 +21,15 @@
|
|
|
21
21
|
- Ajout de nouvelles options d'apparence pour `ClassicButton`
|
|
22
22
|
- Changement propriété principale de `ClassicButtonGroup` pour plus de cohérence
|
|
23
23
|
- Ajout de variables CSS pour configurer l'aspect de divers boutons
|
|
24
|
+
- Ajout d'une propriété SDK permettant d'afficher des tags sur les éléments de
|
|
25
|
+
type `PresentationItem`
|
|
26
|
+
- Ajout de l'api `rubriqueApi`
|
|
24
27
|
|
|
25
28
|
**Fixes**
|
|
26
29
|
|
|
27
30
|
- Correction d'une exception dans `deepEquals` si la comparaison est faite entre
|
|
28
31
|
une variable primitive et un objet
|
|
32
|
+
- Correction du placement du header `PodcastmakerHeader`
|
|
29
33
|
|
|
30
34
|
**Misc**
|
|
31
35
|
|
package/index.ts
CHANGED
|
@@ -194,7 +194,7 @@ export {
|
|
|
194
194
|
type ProviderTts,
|
|
195
195
|
type Voice
|
|
196
196
|
} from "./src/stores/class/transcript/transcriptParams.ts";
|
|
197
|
-
export
|
|
197
|
+
export * from "./src/stores/class/radio/canal";
|
|
198
198
|
export { type Cartouchier } from "./src/stores/class/cartouchier/cartouchier.ts";
|
|
199
199
|
export { type Cartouche, emptyCartouche } from "./src/stores/class/cartouchier/cartouche.ts";
|
|
200
200
|
export { type PlaylistMedia } from "./src/stores/class/radio/playlistMedia";
|
package/package.json
CHANGED
package/src/api/index.ts
CHANGED
package/src/api/radioApi.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Canal } from "../stores/class/radio/canal";
|
|
1
|
+
import { Ambiance, Canal } from "../stores/class/radio/canal";
|
|
2
2
|
import classicApi from "./classicApi";
|
|
3
3
|
import { ModuleApi } from "./apiConnection";
|
|
4
4
|
|
|
@@ -26,7 +26,23 @@ async function getAll(organisationId: string): Promise<Array<Canal>> {
|
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Set the default ambiance for the given canal
|
|
31
|
+
* @param canalId ID of the canal to change
|
|
32
|
+
* @param ambiance New ambiance settings
|
|
33
|
+
* @returns The modified ambiance
|
|
34
|
+
*/
|
|
35
|
+
async function setDefaultAmbiance(canalId: number, ambiance: Ambiance): Promise<Ambiance> {
|
|
36
|
+
return await classicApi.putData<Ambiance>({
|
|
37
|
+
api: ModuleApi.RADIO,
|
|
38
|
+
path: `ambiance/canal/${canalId}/default`,
|
|
39
|
+
dataToSend: ambiance
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
|
|
29
44
|
export const radioApi = {
|
|
30
45
|
get,
|
|
31
|
-
getAll
|
|
46
|
+
getAll,
|
|
47
|
+
setDefaultAmbiance
|
|
32
48
|
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { classicApi, ModuleApi } from "@saooti/octopus-sdk";
|
|
2
|
+
import { Rubrique } from "@/stores/class/rubrique/rubrique";
|
|
3
|
+
import { Rubriquage } from "@/stores/class/rubrique/rubriquage";
|
|
4
|
+
import { useCacheStore } from "../stores/CacheStore";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Find rubriquages according to criterias
|
|
8
|
+
* @param organisationIds List of organisation IDs for which to retrieve the
|
|
9
|
+
* rubriquage
|
|
10
|
+
* @param searchOptions Additional search options
|
|
11
|
+
*/
|
|
12
|
+
async function searchRubriquages(organisationIds: Array<string>, searchOptions?: {
|
|
13
|
+
rubriquageId?: number;
|
|
14
|
+
organisationId?: string|Array<string>;
|
|
15
|
+
query?: string;
|
|
16
|
+
}): Promise<Array<Rubriquage>> {
|
|
17
|
+
return classicApi.fetchData<Array<Rubriquage>>({
|
|
18
|
+
api: ModuleApi.DEFAULT,
|
|
19
|
+
path: 'rubriquage/find',
|
|
20
|
+
parameters: {
|
|
21
|
+
organisationId: organisationIds,
|
|
22
|
+
...searchOptions
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function searchRubriques(searchOptions?: {
|
|
28
|
+
rubriquageId?: number;
|
|
29
|
+
organisationId?: string|Array<string>;
|
|
30
|
+
query?: string;
|
|
31
|
+
}): Promise<Array<Rubrique>> {
|
|
32
|
+
return classicApi.fetchData<Array<Rubrique>>({
|
|
33
|
+
api: ModuleApi.DEFAULT,
|
|
34
|
+
path: 'rubrique/search',
|
|
35
|
+
parameters: searchOptions
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Fetch rubrique data by ID
|
|
41
|
+
* @see getCachedRubrique
|
|
42
|
+
* @param rubriqueId ID of the rubrique to fetch
|
|
43
|
+
* @returns The rubrique
|
|
44
|
+
*/
|
|
45
|
+
async function getRubrique(rubriqueId: number): Promise<Rubrique> {
|
|
46
|
+
return classicApi.fetchData<Rubrique>({
|
|
47
|
+
api: ModuleApi.DEFAULT,
|
|
48
|
+
path: `rubrique/${rubriqueId}`
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Fetch rubrique data by ID
|
|
54
|
+
* If the rubrique is available in the cache, return it from the cache
|
|
55
|
+
* @param rubriqueId ID of the rubrique to fetch
|
|
56
|
+
* @returns The rubrique
|
|
57
|
+
*/
|
|
58
|
+
async function getCachedRubrique(rubriqueId: number): Promise<Rubrique> {
|
|
59
|
+
const cacheStore = useCacheStore();
|
|
60
|
+
return cacheStore.getData(`rubrique-${rubriqueId}`, () => getRubrique(rubriqueId));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const rubriquesApi = {
|
|
64
|
+
getRubrique,
|
|
65
|
+
getCachedRubrique,
|
|
66
|
+
searchRubriquages,
|
|
67
|
+
searchRubriques
|
|
68
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Emission } from "@/stores/class/general/emission";
|
|
2
|
+
import { state } from "../../stores/ParamSdkStore";
|
|
3
|
+
import { useGeneralStore } from "../../stores/GeneralStore";
|
|
4
|
+
import { Podcast } from "../../stores/class/general/podcast";
|
|
5
|
+
import { rubriquesApi } from "../../api";
|
|
6
|
+
import { useDayjs } from "./useDayjs";
|
|
7
|
+
|
|
8
|
+
export const usePresentationItem = () => {
|
|
9
|
+
const generalStore = useGeneralStore();
|
|
10
|
+
const { formatDate } = useDayjs();
|
|
11
|
+
|
|
12
|
+
function iabTags(emission: Emission): Array<string> {
|
|
13
|
+
return generalStore.storedCategories
|
|
14
|
+
.filter(cat => emission.iabIds.includes(cat.id))
|
|
15
|
+
.map(cat => cat.name);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function rubriqueTags(element: Podcast|Emission): Promise<Array<string>> {
|
|
19
|
+
const rubriqueIds: Array<number> = [];
|
|
20
|
+
if (element.rubriqueIds) {
|
|
21
|
+
rubriqueIds.push(...element.rubriqueIds);
|
|
22
|
+
}
|
|
23
|
+
if ('emission' in element && element.emission.rubriqueIds) {
|
|
24
|
+
rubriqueIds.push(...element.emission.rubriqueIds);
|
|
25
|
+
}
|
|
26
|
+
const promises = rubriqueIds.map(rubriquesApi.getCachedRubrique);
|
|
27
|
+
const rubriques = await Promise.all(promises);
|
|
28
|
+
|
|
29
|
+
if (state.presentationItems.tagsRubriquageId) {
|
|
30
|
+
const rubriquageId = state.presentationItems.tagsRubriquageId;
|
|
31
|
+
return rubriques.filter(r => r.rubriquageId === rubriquageId).map(r => r.name);
|
|
32
|
+
} else {
|
|
33
|
+
return rubriques.map(r => r.name);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function tagsFor(element: Podcast|Emission): Promise<Array<string>|undefined> {
|
|
38
|
+
const type = state.presentationItems.tags;
|
|
39
|
+
let tags: Array<string>|undefined = undefined;
|
|
40
|
+
if (type === 'iab') {
|
|
41
|
+
const emission = 'emission' in element ? element.emission : element;
|
|
42
|
+
tags = iabTags(emission);
|
|
43
|
+
} else if (type === 'rubrique') {
|
|
44
|
+
tags = await rubriqueTags(element);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (tags && state.presentationItems.tagsLimit) {
|
|
48
|
+
return tags.slice(0, state.presentationItems.tagsLimit);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return tags;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function additionalInfoFor(element: Podcast|Emission): Array<string>|undefined {
|
|
55
|
+
const prop = state.presentationItems.additionalInfo;
|
|
56
|
+
if (!prop?.length) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const podcast = 'emission' in element ? element : null;
|
|
61
|
+
const emission = podcast?.emission ?? element as Emission;
|
|
62
|
+
|
|
63
|
+
return prop.map(property => {
|
|
64
|
+
if (property === 'date') {
|
|
65
|
+
if (podcast?.pubDate) {
|
|
66
|
+
return formatDate(podcast.pubDate);
|
|
67
|
+
} else {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
} else if (property === 'productor') {
|
|
71
|
+
return emission.orga.name;
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}).filter(p => p !== null);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return { tagsFor, additionalInfoFor };
|
|
78
|
+
};
|
|
@@ -2,33 +2,42 @@
|
|
|
2
2
|
Component to display an emission with its description
|
|
3
3
|
-->
|
|
4
4
|
<template>
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
<PresentationItem
|
|
6
|
+
:name="emission.name"
|
|
7
|
+
:route="route"
|
|
8
|
+
:image-url="emission.imageUrl"
|
|
9
|
+
:description="isDescription ? emission.description : undefined"
|
|
10
|
+
:vertical="isVertical"
|
|
11
|
+
:tags="tags"
|
|
12
|
+
:additional-info="additionalInfoFor(emission)"
|
|
13
|
+
/>
|
|
12
14
|
</template>
|
|
13
15
|
|
|
14
16
|
<script setup lang="ts">
|
|
15
17
|
import { Emission } from "@/stores/class/general/emission";
|
|
16
18
|
import PresentationItem from "../../layouts/PresentationItem.vue";
|
|
17
|
-
import { computed } from "vue";
|
|
19
|
+
import { computed, ref, watch } from "vue";
|
|
18
20
|
import { RouteLocationRaw } from "vue-router";
|
|
21
|
+
import { usePresentationItem } from "../../composable/usePresentationItem";
|
|
19
22
|
|
|
20
23
|
//Props
|
|
21
24
|
const props = defineProps<{
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
/** The emission to display */
|
|
26
|
+
emission: Emission;
|
|
27
|
+
/** When true display the card vertically */
|
|
28
|
+
isVertical?: boolean;
|
|
29
|
+
/** When true also display the description */
|
|
30
|
+
isDescription?: boolean;
|
|
28
31
|
}>();
|
|
29
32
|
|
|
33
|
+
const tags = ref([]);
|
|
34
|
+
const { tagsFor, additionalInfoFor } = usePresentationItem();
|
|
35
|
+
|
|
36
|
+
watch(props.emission, async () => {
|
|
37
|
+
tags.value = await tagsFor(props.emission);
|
|
38
|
+
}, { immediate: true });
|
|
39
|
+
|
|
30
40
|
const route = computed((): RouteLocationRaw => {
|
|
31
|
-
|
|
41
|
+
return { name: 'emission', params: { emissionId: props.emission.emissionId } };
|
|
32
42
|
});
|
|
33
|
-
|
|
34
43
|
</script>
|
|
@@ -1,72 +1,87 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
<div class="page-element-title-container">
|
|
3
|
+
<div class="page-element-title">
|
|
4
|
+
<h1>{{ pageTitle }}</h1>
|
|
5
|
+
</div>
|
|
6
|
+
<div class="page-element-bg" :style="backgroundDisplay" />
|
|
5
7
|
</div>
|
|
6
|
-
<div class="page-element-bg" :style="backgroundDisplay" />
|
|
7
|
-
</div>
|
|
8
8
|
</template>
|
|
9
9
|
|
|
10
10
|
<script setup lang="ts">
|
|
11
|
-
import { computed } from "vue";
|
|
12
|
-
import {useImageProxy} from "../../composable/useImageProxy";
|
|
11
|
+
import { computed, onMounted } from "vue";
|
|
12
|
+
import { useImageProxy } from "../../composable/useImageProxy";
|
|
13
13
|
|
|
14
14
|
//Props
|
|
15
15
|
const props = defineProps({
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
pageTitle: { default: undefined, type: String },
|
|
17
|
+
imgUrl: { default: undefined, type: String },
|
|
18
18
|
})
|
|
19
19
|
|
|
20
|
+
onMounted(() => {
|
|
21
|
+
const elt = document.querySelector('.page-element-title-container');
|
|
22
|
+
|
|
23
|
+
// Retrieve header
|
|
24
|
+
const header = document.getElementsByTagName('header');
|
|
25
|
+
if (header.length) {
|
|
26
|
+
// Get header height
|
|
27
|
+
const height = (header[0] as HTMLElement).offsetHeight;
|
|
28
|
+
// Update PM header position according to header height
|
|
29
|
+
elt.style.setProperty('--top', height + 'px');
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
20
33
|
//Composables
|
|
21
34
|
const { useProxyImageUrl } = useImageProxy();
|
|
22
35
|
|
|
23
36
|
//Computed
|
|
24
37
|
const backgroundDisplay = computed(() => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
38
|
+
if (!props.imgUrl) {
|
|
39
|
+
return "";
|
|
40
|
+
}
|
|
41
|
+
return `background-image: url('${useProxyImageUrl(
|
|
42
|
+
props.imgUrl,
|
|
43
|
+
"250",
|
|
44
|
+
)}');`;
|
|
32
45
|
});
|
|
33
46
|
</script>
|
|
34
47
|
|
|
35
48
|
<style lang="scss">
|
|
36
49
|
.octopus-app {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
50
|
+
.page-element.page-element-podcastmaker {
|
|
51
|
+
margin-top: 11rem;
|
|
52
|
+
}
|
|
40
53
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
position: absolute;
|
|
44
|
-
right: 0;
|
|
45
|
-
left: 0;
|
|
46
|
-
top: 0;
|
|
54
|
+
.page-element-title-container {
|
|
55
|
+
--top: 0;
|
|
47
56
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
background: black;
|
|
58
|
+
position: absolute;
|
|
59
|
+
right: 0;
|
|
60
|
+
left: 0;
|
|
61
|
+
top: var(--top);
|
|
62
|
+
|
|
63
|
+
.page-element-bg {
|
|
64
|
+
height: 15rem;
|
|
65
|
+
opacity: 0.5;
|
|
66
|
+
filter: blur(8px);
|
|
67
|
+
background-position: center;
|
|
68
|
+
background-repeat: no-repeat;
|
|
69
|
+
background-size: cover;
|
|
70
|
+
}
|
|
56
71
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
72
|
+
.page-element-title {
|
|
73
|
+
position: absolute;
|
|
74
|
+
inset: 0;
|
|
75
|
+
z-index: 2;
|
|
76
|
+
display: flex;
|
|
77
|
+
justify-content: center;
|
|
78
|
+
align-items: center;
|
|
64
79
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
80
|
+
h1 {
|
|
81
|
+
color: white !important;
|
|
82
|
+
font-size: 2rem;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
69
85
|
}
|
|
70
|
-
}
|
|
71
86
|
}
|
|
72
87
|
</style>
|
|
@@ -2,37 +2,39 @@
|
|
|
2
2
|
Simple component to display a few podcasts
|
|
3
3
|
-->
|
|
4
4
|
<template>
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
5
|
+
<PresentationLayout
|
|
6
|
+
v-if="!loading && !error"
|
|
7
|
+
:title="title"
|
|
8
|
+
:items="podcasts"
|
|
9
|
+
:route="href"
|
|
10
|
+
:button-text="buttonText"
|
|
11
|
+
>
|
|
12
|
+
<template #item="{ item, first }">
|
|
13
|
+
<PresentationItem
|
|
14
|
+
:class="!isPhone && first ? 'me-3' : ''"
|
|
15
|
+
:name="item.title"
|
|
16
|
+
:route="route(item)"
|
|
17
|
+
:image-url="item.imageUrl"
|
|
18
|
+
:description="item.description"
|
|
19
|
+
:vertical="!isPhone && first"
|
|
20
|
+
:tags="tags.get(item.podcastId)"
|
|
21
|
+
:additional-info="additionalInfoFor(item)"
|
|
22
|
+
>
|
|
23
|
+
<template #after-image>
|
|
24
|
+
<PodcastPlayButton
|
|
25
|
+
:podcast="item"
|
|
26
|
+
:hide-play="false"
|
|
27
|
+
:show-processing="false"
|
|
28
|
+
/>
|
|
29
|
+
</template>
|
|
30
|
+
</PresentationItem>
|
|
27
31
|
</template>
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
:error-text="error ? $t(`Error`) : undefined"
|
|
35
|
-
/>
|
|
32
|
+
</PresentationLayout>
|
|
33
|
+
<ClassicLoading
|
|
34
|
+
v-else
|
|
35
|
+
:loading-text="loading ? $t('Loading emissions ...') : undefined"
|
|
36
|
+
:error-text="error ? $t(`Error`) : undefined"
|
|
37
|
+
/>
|
|
36
38
|
</template>
|
|
37
39
|
|
|
38
40
|
<script setup lang="ts">
|
|
@@ -40,7 +42,7 @@ import classicApi from "../../../api/classicApi";
|
|
|
40
42
|
import {useErrorHandler} from "../../composable/useErrorHandler";
|
|
41
43
|
import ClassicLoading from "../../form/ClassicLoading.vue";
|
|
42
44
|
import { Emission } from "@/stores/class/general/emission";
|
|
43
|
-
import { onMounted, Ref, ref } from "vue";
|
|
45
|
+
import { onMounted, reactive, Ref, ref, watch } from "vue";
|
|
44
46
|
import { AxiosError } from "axios";
|
|
45
47
|
import {useResizePhone} from "../../composable/useResizePhone";
|
|
46
48
|
import { ListClassicReturn } from "../../../stores/class/general/listReturn";
|
|
@@ -52,89 +54,101 @@ import PresentationItem from "../../layouts/PresentationItem.vue";
|
|
|
52
54
|
import PodcastPlayButton from "./PodcastPlayButton.vue";
|
|
53
55
|
import { RouteLocationRaw } from "vue-router";
|
|
54
56
|
import { podcastApi, PodcastSort } from "../../../api/podcastApi";
|
|
57
|
+
import { usePresentationItem } from "../../composable/usePresentationItem";
|
|
55
58
|
|
|
56
59
|
//Props
|
|
57
60
|
const props = defineProps({
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
organisationId: { default: undefined, type: String },
|
|
62
|
+
title: { default: "", type: String },
|
|
63
|
+
href: { default: undefined, type: String },
|
|
64
|
+
buttonText: { default: undefined, type: String },
|
|
65
|
+
isDescription: { default: false, type: Boolean },
|
|
66
|
+
rubriquesId: { default: [], type: Array<number> },
|
|
64
67
|
})
|
|
65
68
|
|
|
66
69
|
//Data
|
|
67
70
|
const loading = ref(true);
|
|
68
71
|
const error = ref(false);
|
|
69
72
|
const podcasts: Ref<Array<Podcast>> = ref([]);
|
|
73
|
+
const tags = reactive(new Map<number, Array<string>>());
|
|
70
74
|
|
|
71
75
|
//Composables
|
|
72
76
|
const { isPhone } = useResizePhone();
|
|
73
|
-
const {handle403} = useErrorHandler();
|
|
77
|
+
const { handle403 } = useErrorHandler();
|
|
78
|
+
const { tagsFor, additionalInfoFor } = usePresentationItem();
|
|
74
79
|
|
|
75
|
-
onMounted(
|
|
80
|
+
onMounted(fetchNext);
|
|
81
|
+
|
|
82
|
+
watch(podcasts, async () => {
|
|
83
|
+
podcasts.value.forEach(async (podcast) => {
|
|
84
|
+
if (!tags.has(podcast.podcastId)) {
|
|
85
|
+
const t = await tagsFor(podcast);
|
|
86
|
+
tags.set(podcast.podcastId, t);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
});
|
|
76
90
|
|
|
77
91
|
//Methods
|
|
78
92
|
async function fetchNext(): Promise<void> {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
93
|
+
loading.value = true;
|
|
94
|
+
try {
|
|
95
|
+
// Retrieve latest emissions
|
|
96
|
+
const emissions = await classicApi.fetchData<ListClassicReturn<Emission>>({
|
|
97
|
+
api: 0,
|
|
98
|
+
path: "emission/search",
|
|
99
|
+
parameters: {
|
|
100
|
+
first: 0,
|
|
101
|
+
size: 5,
|
|
102
|
+
organisationId: props.organisationId,
|
|
103
|
+
sort: "LAST_PODCAST_DESC",
|
|
104
|
+
rubriqueId: props.rubriquesId
|
|
105
|
+
},
|
|
106
|
+
specialTreatement: true,
|
|
107
|
+
});
|
|
94
108
|
|
|
95
|
-
|
|
109
|
+
const promises: Array<Promise<SimplifiedPodcast>> = [];
|
|
96
110
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
111
|
+
for (let i = 0; i < emissions.result.length; i++) {
|
|
112
|
+
promises.push(podcastApi.search({
|
|
113
|
+
first: 0,
|
|
114
|
+
size: 1,
|
|
115
|
+
organisationId: [props.organisationId],
|
|
116
|
+
emissionId: [emissions.result[i].emissionId],
|
|
117
|
+
sort: PodcastSort.DATE,
|
|
118
|
+
rubriqueId: props.rubriquesId
|
|
119
|
+
}).then(r => r.result[0]));
|
|
120
|
+
}
|
|
107
121
|
|
|
108
|
-
|
|
109
|
-
|
|
122
|
+
// Retrieve the podcasts for these emissions
|
|
123
|
+
const data = await Promise.all(promises);
|
|
110
124
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
125
|
+
podcasts.value = podcasts.value.concat(
|
|
126
|
+
data.filter((em: SimplifiedPodcast | null) => null !== em && undefined !== em).map(p => {
|
|
127
|
+
// Get emission from podcast
|
|
128
|
+
const emission = emissions.result.find(e => e.emissionId === p.emissionId);
|
|
129
|
+
// Create full podcast from simplified + emission
|
|
130
|
+
return simplifiedToFull(p, emission.orga, emission);
|
|
131
|
+
})
|
|
132
|
+
);
|
|
119
133
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
134
|
+
// Sort podcasts by pub date so that the most recent one is focused
|
|
135
|
+
podcasts.value.sort((p1, p2) => {
|
|
136
|
+
return new Date(p2.pubDate).getTime() - new Date(p1.pubDate).getTime();
|
|
137
|
+
});
|
|
124
138
|
|
|
139
|
+
loading.value = false;
|
|
140
|
+
} catch (errorWs) {
|
|
141
|
+
console.error(errorWs);
|
|
142
|
+
handle403(errorWs as AxiosError);
|
|
143
|
+
error.value = true;
|
|
144
|
+
}
|
|
125
145
|
loading.value = false;
|
|
126
|
-
} catch (errorWs) {
|
|
127
|
-
console.error(errorWs);
|
|
128
|
-
handle403(errorWs as AxiosError);
|
|
129
|
-
error.value = true;
|
|
130
|
-
}
|
|
131
|
-
loading.value = false;
|
|
132
146
|
}
|
|
133
147
|
|
|
134
148
|
function route(podcast: Podcast): RouteLocationRaw {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
149
|
+
return {
|
|
150
|
+
name: 'podcast',
|
|
151
|
+
params: { podcastId: podcast.podcastId }
|
|
152
|
+
}
|
|
139
153
|
}
|
|
140
154
|
</script>
|