Files
geovisio-website/src/views/MySequencesView.vue
2023-08-07 15:33:25 +02:00

365 lines
8.9 KiB
Vue

<template>
<main class="entry-page">
<h1 class="sequences-title">{{ $t('pages.sequences.title') }}</h1>
<ul v-if="!isLoading" class="sequence-list">
<li class="sequence-item">
<div class="sequence-header-item"></div>
<div class="sequence-header-item">
<Button
:text="$t('pages.sequences.sequence_name')"
look="link--grey"
icon="bi bi-arrow-down-up"
data-test="button-sort-title"
@trigger="sortAlpha('title')"
/>
</div>
<div class="sequence-header-item">
<Button
:text="$t('pages.sequences.sequence_photos')"
look="link--grey"
icon="bi bi-arrow-down-up"
data-test="button-sort-number"
@trigger="sortNum('num')"
/>
</div>
<div class="sequence-header-item">
<Button
:text="$t('pages.sequences.sequence_date')"
look="link--grey"
icon="bi bi-arrow-down-up"
data-test="button-sort-date"
@trigger="sortNum('date')"
/>
</div>
<div class="sequence-header-item">
<Button
:text="$t('pages.sequences.sequence_status')"
look="link--grey"
icon="bi bi-arrow-down-up"
data-test="button-sort-date"
@trigger="sortAlpha('geovisio:status')"
/>
</div>
</li>
<li
v-if="userSequences.length"
v-for="item in userSequences"
class="sequence-item"
>
<router-link
class="button-item"
:to="{
name: 'sequence',
params: { id: item.id }
}"
>
<div class="wrapper-thumb">
<img
v-if="item['stats:items'].count > 0"
:src="`${item.href}/thumb.jpg`"
lazy="loading"
alt=""
class="thumb"
/>
<div class="wrapper-thumb-hover">
<img
v-if="item['stats:items'].count > 0"
:src="`${item.href}/thumb.jpg`"
lazy="loading"
alt=""
class="thumb-hover"
/>
</div>
</div>
<div>
<span>
{{ item.title }}
</span>
</div>
<div>
<i class="bi bi-images"></i>
<span>
{{ item['stats:items'].count }}
</span>
</div>
<div>
<span>
{{
formatDate(
item.extent.temporal.interval[0][0],
'Do MMMM YYYY HH:mm:ss'
)
}}
</span>
</div>
<div>
<span>{{ sequenceStatus(item['geovisio:status']) }}</span>
</div>
</router-link>
</li>
<div v-else class="no-sequence">
<p class="no-sequence-text">
{{ $t('pages.sequences.no_sequences_text') }}
</p>
<Link
:text="$t('general.header.upload_text')"
look="button"
:route="{ name: 'share-pictures' }"
/>
</div>
</ul>
<div v-else class="loader">
<Loader look="sm" :is-loaded="false" />
</div>
<Toast :text="toastText" :look="toastLook" @trigger="toastText = ''" />
</main>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { useSequenceStore } from '@/store/sequence'
import { storeToRefs } from 'pinia'
import axios from 'axios'
import Button from '@/components/Button.vue'
import Link from '@/components/Link.vue'
import Toast from '@/components/Toast.vue'
import Loader from '@/components/Loader.vue'
import type {
LinkInterface,
ExtentLinkInterface
} from './interfaces/MySequencesView'
import { formatDate } from '@/utils/dates'
const { t } = useI18n()
const sequenceStore = useSequenceStore()
const { toastText, toastLook } = storeToRefs(sequenceStore)
let userSequences = ref<LinkInterface[]>([])
let isSorted = ref<boolean>(false)
let isLoading = ref<boolean>(false)
function sequenceStatus(status: string): string {
if (status === 'ready') return t('pages.sequences.sequence_published')
if (status === 'waiting-for-process')
return t('pages.sequences.sequence_waiting')
return t('pages.sequences.sequence_hidden')
}
function sortAlpha<TKey extends keyof LinkInterface>(key: TKey): void {
const sorted = userSequences.value.sort(
(
a: { [K in TKey]: LinkInterface[TKey] },
b: { [K in TKey]: LinkInterface[TKey] }
) => {
if (a[key] < b[key]) return !isSorted.value ? -1 : 1
if (a[key] > b[key]) return !isSorted.value ? 1 : -1
return 0
}
)
isSorted.value = !isSorted.value
userSequences.value = sorted
}
function sortNum(type: string): void {
let aa, bb: number
const sorted = userSequences.value.sort(
(a: ExtentLinkInterface, b: ExtentLinkInterface) => {
aa = new Date(a.extent.temporal.interval[0][0]).getTime()
bb = new Date(b.extent.temporal.interval[0][0]).getTime()
if (type === 'num') {
aa = Number(a['stats:items'].count)
bb = Number(b['stats:items'].count)
}
if (aa < bb) return !isSorted.value ? -1 : 1
if (aa > bb) return !isSorted.value ? 1 : -1
return 0
}
)
isSorted.value = !isSorted.value
userSequences.value = sorted
}
onMounted(async () => {
isLoading.value = true
try {
const { data } = await axios.get('api/users/me/catalog')
const relChild = data.links.filter(
(el: LinkInterface) => el.rel === 'child'
)
userSequences.value = relChild
isLoading.value = false
} catch (err) {
isLoading.value = false
console.log(err)
}
})
</script>
<style lang="scss" scoped>
.entry-page {
padding-right: toRem(8);
padding-left: toRem(8);
padding-top: toRem(11);
min-height: calc(100vh - #{toRem(8)});
}
.sequences-title {
@include text(h1);
margin-bottom: toRem(4);
}
.sequence-list {
box-shadow: 0px 2px 30px 0px #0000000f;
border-radius: toRem(2);
padding: 0;
}
.sequence-item {
@include text(s-regular);
border: none;
display: flex;
justify-content: center;
margin: auto;
background-color: var(--blue-pale);
&:last-child {
border-bottom-right-radius: toRem(2);
border-bottom-left-radius: toRem(2);
.button-item {
border-bottom-right-radius: toRem(2);
border-bottom-left-radius: toRem(2);
}
}
&:first-child {
margin-bottom: toRem(1);
padding: toRem(1) toRem(3);
border-bottom: toRem(0.1) solid var(--grey);
border-radius: toRem(2) toRem(2) 0rem 0rem;
background-color: var(--white);
}
&:nth-child(2n) {
background-color: var(--white);
}
}
.wrapper-title {
display: flex;
align-items: center;
}
.wrapper-thumb {
position: relative;
}
.wrapper-thumb-hover {
display: none;
border-radius: toRem(0.3);
border: toRem(1) solid var(--grey);
position: absolute;
bottom: 0;
height: toRem(15);
z-index: 1;
}
.thumb-hover {
height: 100%;
}
.wrapper-thumb:hover {
.wrapper-thumb-hover {
display: block;
}
}
.thumb {
height: 100%;
width: 100%;
object-fit: cover;
border-radius: toRem(0.5);
position: relative;
}
.button-item {
display: flex;
align-items: center;
width: 100%;
padding: toRem(2) toRem(3);
background-color: transparent;
border: none;
text-decoration: none;
& > * {
padding: toRem(1);
text-align: initial;
width: 31%;
color: var(--black);
}
> :first-child {
color: var(--blue);
width: toRem(6);
}
& > :first-child {
padding: 0;
margin-right: toRem(2);
}
& > :nth-child(2) {
color: var(--blue);
}
&:hover {
background-color: var(--blue);
& > * {
color: var(--white);
}
}
}
.bi-images {
margin-right: toRem(0.5);
}
.sequence-header-item {
width: 31%;
&:first-child {
margin-right: toRem(2);
}
&:first-child {
width: toRem(6);
}
}
.no-sequence {
padding-top: toRem(2);
padding-bottom: toRem(4);
margin: auto;
width: fit-content;
text-align: center;
@include text(m-regular);
}
.no-sequence-text {
margin-bottom: toRem(4);
}
.loader {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
margin-top: toRem(20);
}
@media (max-width: toRem(76.8)) {
.entry-page {
padding-right: toRem(2);
padding-left: toRem(2);
padding-top: toRem(14);
min-height: calc(100vh - #{toRem(11)});
}
.button-item,
.sequence-item:first-child {
padding-right: toRem(1);
padding-left: toRem(1);
}
}
@media (max-width: toRem(50)) {
.button-item {
flex-direction: column;
align-items: center;
& > * {
text-align: center;
width: 100%;
}
.wrapper-thumb {
margin-right: 0;
}
}
.sequence-item:first-child {
display: none;
}
.sequence-item {
border-top-right-radius: toRem(1);
border-top-left-radius: toRem(1);
}
}
</style>