Skip to content

Commit

Permalink
feat(bouquet): show reuses
Browse files Browse the repository at this point in the history
  • Loading branch information
abulte committed Apr 2, 2024
1 parent c707dab commit 0953304
Show file tree
Hide file tree
Showing 12 changed files with 278 additions and 194 deletions.
110 changes: 110 additions & 0 deletions src/components/ReusesList.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<script setup lang="ts">
import { onMounted, ref, type Ref, type PropType } from 'vue'
import type { Topic } from '@/model'
import { type Reuse, type ReuseType, ReuseModel } from '@/model/reuse'
import ReusesAPI from '@/services/api/resources/ReusesAPI'
import { useReuseStore } from '@/store/ReuseStore'
import { useTopicStore } from '@/store/TopicStore'
import { formatDate } from '@/utils'
const props = defineProps({
model: {
type: String as PropType<keyof typeof ReuseModel>,
required: true
},
objectId: {
type: String,
required: true
}
})
const reuseStore = useReuseStore()
const reuseApi = new ReusesAPI()
const reuses: Ref<Reuse[]> = ref([])
const types: Ref<ReuseType[]> = ref([])
const crop = (value: string) => {
return value.length <= 40 ? value : `${value.slice(0, 40)}...`
}
const reuseDescription = (r: Reuse) => {
const desc = `Publié le ${formatDate(r.created_at, true)}`
if (r.organization?.name) {
return `${desc} par ${r.organization?.name}`
} else {
return `${desc} par ${r.owner?.first_name} ${r.owner?.last_name}`
}
}
const getType = (id: string) => {
const type = types.value.find((t) => t.id === id)
return type?.label || ''
}
onMounted(() => {
switch (props.model) {
case 'dataset':
reuseStore
.loadReusesForDataset(props.objectId)
.then((r) => (reuses.value = r))
break
case 'topic':
useTopicStore()
.load(props.objectId)
.then((t: Topic) => {
reuseApi
.getReusesFromRel(t.reuses)
.then((data) => (reuses.value = data))
})
break
default:
break
}
reuseStore.getTypes().then((data) => {
types.value = data
})
})
</script>

<template>
<div
v-if="!reuses.length"
class="fr-grid-row flex-direction-column fr-grid-row--middle fr-mt-5w"
>
<img height="105" width="130" loading="lazy" src="/blank_state/reuse.svg" />
<p class="fr-h6 fr-mt-2w fr-mb-5v text-center">
Il n'y a pas encore de réutilisation pour ce {{ ReuseModel[model] }}.
</p>
<p>
<a
class="fr-btn fr-btn--secondary fr-btn--secondary-grey-500 fr-ml-1w"
href="https://guides.data.gouv.fr/publier-des-donnees/guide-data.gouv.fr/reutilisations"
>
Qu'est-ce qu'une réutilisation ?
</a>
</p>
</div>
<div v-else>
<h2 class="fr-mt-4w">Réutilisations</h2>
<ul class="fr-grid-row fr-grid-row--gutters es__tiles__list">
<li
v-for="r in reuses"
:key="r.id"
class="fr-col-12 fr-col-md-6 fr-col-lg-3"
>
<DsfrCard
:link="r.page"
:style="`max-width: 400px; max-height: 400px`"
:title="crop(r.title)"
:detail="getType(r.type)"
:description="reuseDescription(r)"
size="sm"
:img-src="
r.image_thumbnail || r.organization?.logo || r.owner?.avatar
"
/>
</li>
</ul>
</div>
</template>
15 changes: 14 additions & 1 deletion src/custom/ecospheres/views/bouquets/BouquetDetailView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { useLoading } from 'vue-loading-overlay'
import { useRouter } from 'vue-router'
import DiscussionsList from '@/components/DiscussionsList.vue'
import ReusesList from '@/components/ReusesList.vue'
import config from '@/config'
import BouquetDatasetList, {
getDatasetListTitle
Expand Down Expand Up @@ -189,7 +190,11 @@ onMounted(() => {
<DsfrTabs
class="fr-mt-2w"
tab-list-name="Groupes d'attributs du bouquet"
:tab-titles="[{ title: 'Données' }, { title: 'Discussions' }]"
:tab-titles="[
{ title: 'Données' },
{ title: 'Discussions' },
{ title: 'Réutilisations' }
]"
:initial-selected-index="0"
:selected-tab-index="selectedTabIndex"
@select-tab="(idx: number) => (selectedTabIndex = idx)"
Expand All @@ -215,6 +220,14 @@ onMounted(() => {
subject-class="Topic"
/>
</DsfrTabContent>
<!-- Réutilisations -->
<DsfrTabContent
panel-id="tab-content-2"
tab-id="tab-2"
:selected="selectedTabIndex === 2"
>
<ReusesList model="topic" :object-id="bouquet.id" />
</DsfrTabContent>
</DsfrTabs>
</div>
</template>
Expand Down
5 changes: 3 additions & 2 deletions src/model/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Owned } from '@etalab/data.gouv.fr-components'
import type { Owned, Rel } from '@etalab/data.gouv.fr-components'

import type { SpatialField } from './spatial'

Expand Down Expand Up @@ -87,7 +87,8 @@ type Topic = Owned & {
id: string
page: string
private: boolean
reuses: []
reuses: Rel
datasets: Rel
slug: string
tags: string[]
uri: string
Expand Down
4 changes: 4 additions & 0 deletions src/model/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,8 @@ export interface ResourceData {
type: ResourceType
}

export interface ResourceDataWithQuery extends ResourceData {
query: string
}

export type { Resource }
26 changes: 26 additions & 0 deletions src/model/reuse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { Owned } from '@etalab/data.gouv.fr-components'

import type { GenericResponse } from './api'

export type Reuse = Owned & {
id: string
title: string
created_at: string
image_thumbnail?: string
type: string
page: string
}

export interface ReuseResponse extends GenericResponse {
data: Reuse[]
}

export interface ReuseType {
id: string
label: string
}

export enum ReuseModel {
dataset = 'jeu de donnée',
topic = 'bouquet'
}
21 changes: 0 additions & 21 deletions src/services/api/resources/ReusesAPI.js

This file was deleted.

41 changes: 41 additions & 0 deletions src/services/api/resources/ReusesAPI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import type { Rel } from '@etalab/data.gouv.fr-components'

import type { Reuse, ReuseResponse } from '@/model/reuse'

import DatagouvfrAPI from '../DatagouvfrAPI'

export default class ReusesAPI extends DatagouvfrAPI {
endpoint = 'reuses'

/**
* Get reuses for a dataset
*/
async getReusesForDataset(datasetId: string): Promise<ReuseResponse> {
return await this.request({
url: this.url(true),
method: 'get',
params: {
dataset: datasetId
}
})
}

/**
* Get reuses from rel
*/
async getReusesFromRel(rel: Rel): Promise<Reuse[]> {
let response = await this.request({
url: rel.href,
method: 'get'
})
let reuses = response.data
while (response.next_page !== null) {
response = await this.request({
url: response.next_page,
method: 'get'
})
reuses = [...reuses, ...response.data]
}
return reuses
}
}
50 changes: 0 additions & 50 deletions src/store/ReuseStore.js

This file was deleted.

47 changes: 47 additions & 0 deletions src/store/ReuseStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { defineStore } from 'pinia'

import type { Reuse, ReuseType } from '@/model/reuse'

import ReusesAPI from '../services/api/resources/ReusesAPI'

const reusesAPI = new ReusesAPI()

interface RootState {
data: Record<string, Reuse[]>
}

export const useReuseStore = defineStore('reuse', {
state: (): RootState => ({
data: {}
}),
actions: {
/**
* Get reuses for a dataset from store
*/
getReusesForDataset(datasetId: string) {
return this.data[datasetId]
},
/**
* Async function to trigger API fetch of reuses for an object
*/
async loadReusesForDataset(datasetId: string) {
const existing = this.getReusesForDataset(datasetId)
if (existing !== undefined) return existing
const reuses = await reusesAPI.getReusesForDataset(datasetId)
this.addReuses(datasetId, reuses.data)
return this.getReusesForDataset(datasetId)
},
/**
* Store the result of a reuses fetch operation for a dataset in store
*/
addReuses(datasetId: string, reuses: Reuse[]) {
this.data[datasetId] = reuses
},
/**
* Get reuses types from the API
*/
async getTypes(): Promise<ReuseType[]> {
return await reusesAPI.get('types')
}
}
})
2 changes: 1 addition & 1 deletion src/store/TopicStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const useTopicStore = defineStore('topic', {
async loadTopicsFromList(topics: Topic[]) {
this.data = []
for (const topic of topics) {
const res = await topicsAPI.get(topic.id)
const res = await topicsAPIv2.get(topic.id)
this.data.push(res)
}
},
Expand Down
17 changes: 12 additions & 5 deletions src/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,17 @@ export const stripFromMarkdown = (value) => {
* Format date
*
*/
export const formatDate = (dateString) => {
export const formatDate = (dateString, short = false) => {
const date = new Date(dateString)
return new Intl.DateTimeFormat('default', {
dateStyle: 'full',
timeStyle: 'short'
}).format(date)
const params = short
? {
day: 'numeric',
month: 'short',
year: 'numeric'
}
: {
dateStyle: 'full',
timeStyle: 'short'
}
return new Intl.DateTimeFormat('default', params).format(date)
}
Loading

0 comments on commit 0953304

Please sign in to comment.