fix(frontend): simplify collections view and restore invite access
Unify collections and shared items under a single Collections tab while keeping Archive separate, and fix card layering so menus render correctly. Restore invite discoverability by adding navbar access to /invites and add missing i18n keys to prevent raw key labels in collections/invites UI.
This commit is contained in:
@@ -53,21 +53,21 @@
|
|||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<figure>
|
<figure class="m-0 h-full">
|
||||||
{#if sortedImages && sortedImages.length > 0}
|
{#if sortedImages && sortedImages.length > 0}
|
||||||
<div class="carousel w-full relative">
|
<div class="carousel w-full h-full relative">
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<div class="carousel-item w-full block">
|
<div class="carousel-item w-full h-full block">
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
<!-- svelte-ignore a11y-missing-attribute -->
|
<!-- svelte-ignore a11y-missing-attribute -->
|
||||||
<a
|
<a
|
||||||
on:click|stopPropagation={() => openImageModal(currentSlide)}
|
on:click|stopPropagation={() => openImageModal(currentSlide)}
|
||||||
class="cursor-pointer relative group"
|
class="cursor-pointer relative group block h-full w-full"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src={sortedImages[currentSlide].image}
|
src={sortedImages[currentSlide].image}
|
||||||
class="w-full h-48 object-cover transition-all group-hover:brightness-110"
|
class="w-full h-full object-cover transition-all group-hover:brightness-110"
|
||||||
alt={name || 'Image'}
|
alt={name || 'Image'}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -165,7 +165,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<!-- Fallback with emoji icon as main image -->
|
<!-- Fallback with emoji icon as main image -->
|
||||||
<div class="w-full h-48 relative flex items-center justify-center">
|
<div class="w-full h-full relative flex items-center justify-center">
|
||||||
{#if icon}
|
{#if icon}
|
||||||
<!-- Clean background with emoji as the focal point -->
|
<!-- Clean background with emoji as the focal point -->
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -113,6 +113,7 @@
|
|||||||
const navigationItems = [
|
const navigationItems = [
|
||||||
{ path: '/locations', icon: MapMarker, label: 'locations.locations' },
|
{ path: '/locations', icon: MapMarker, label: 'locations.locations' },
|
||||||
{ path: '/collections', icon: FormatListBulletedSquare, label: 'navbar.collections' },
|
{ path: '/collections', icon: FormatListBulletedSquare, label: 'navbar.collections' },
|
||||||
|
{ path: '/invites', icon: AccountMultiple, label: 'invites.title' },
|
||||||
{ path: '/worldtravel', icon: Earth, label: 'navbar.worldtravel' },
|
{ path: '/worldtravel', icon: Earth, label: 'navbar.worldtravel' },
|
||||||
{ path: '/map', icon: MapIcon, label: 'navbar.map' },
|
{ path: '/map', icon: MapIcon, label: 'navbar.map' },
|
||||||
{ path: '/calendar', icon: Calendar, label: 'navbar.calendar' },
|
{ path: '/calendar', icon: Calendar, label: 'navbar.calendar' },
|
||||||
|
|||||||
@@ -192,6 +192,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
let isWarningModalOpen: boolean = false;
|
let isWarningModalOpen: boolean = false;
|
||||||
|
|
||||||
|
$: isOwner = !!user && String(user.uuid) === String(collection.user);
|
||||||
|
$: isSharedMember =
|
||||||
|
!!user &&
|
||||||
|
Array.isArray(collection.shared_with) &&
|
||||||
|
collection.shared_with.some((sharedUserId) => String(sharedUserId) === String(user.uuid));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if isWarningModalOpen}
|
{#if isWarningModalOpen}
|
||||||
@@ -210,18 +216,20 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="bg-base-100 rounded-2xl shadow hover:shadow-xl transition-all overflow-hidden w-full cursor-pointer group"
|
class="bg-base-100 rounded-2xl shadow hover:shadow-xl transition-all w-full cursor-pointer group"
|
||||||
role="link"
|
role="link"
|
||||||
aria-label={collection.name}
|
aria-label={collection.name}
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
on:click={goToCollection}
|
on:click={goToCollection}
|
||||||
on:keydown={handleCardKeydown}
|
on:keydown={handleCardKeydown}
|
||||||
>
|
>
|
||||||
<div class="relative h-56 overflow-hidden card-carousel-tall">
|
<div class="relative h-56 card-carousel-tall rounded-t-2xl">
|
||||||
<CardCarousel images={location_images} name={collection.name} icon="📚" />
|
<div class="absolute inset-0 overflow-hidden rounded-t-2xl">
|
||||||
<div
|
<CardCarousel images={location_images} name={collection.name} icon="📚" />
|
||||||
class="absolute inset-0 bg-gradient-to-t from-black/70 via-black/20 to-transparent pointer-events-none z-10"
|
<div
|
||||||
></div>
|
class="absolute inset-0 bg-gradient-to-t from-black/70 via-black/20 to-transparent pointer-events-none z-10"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="absolute top-3 left-3 z-20 flex gap-1.5">
|
<div class="absolute top-3 left-3 z-20 flex gap-1.5">
|
||||||
{#if collection.status === 'folder'}
|
{#if collection.status === 'folder'}
|
||||||
@@ -267,7 +275,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="absolute top-3 right-3 z-20 flex items-center gap-1.5">
|
<div class="absolute top-3 right-3 z-30 flex items-center gap-1.5">
|
||||||
<div
|
<div
|
||||||
class="tooltip tooltip-left"
|
class="tooltip tooltip-left"
|
||||||
data-tip={collection.is_public ? $t('adventures.public') : $t('adventures.private')}
|
data-tip={collection.is_public ? $t('adventures.public') : $t('adventures.private')}
|
||||||
@@ -284,8 +292,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if user && user.uuid == collection.user && type != 'link' && type != 'viewonly'}
|
{#if isOwner && type != 'link' && type != 'viewonly'}
|
||||||
<div class="dropdown dropdown-end">
|
<div class="dropdown dropdown-end z-30">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-ghost bg-black/40 backdrop-blur-sm text-white rounded-full w-7 h-7 p-0 min-h-0 border-0 hover:bg-black/55"
|
class="btn btn-ghost bg-black/40 backdrop-blur-sm text-white rounded-full w-7 h-7 p-0 min-h-0 border-0 hover:bg-black/55"
|
||||||
@@ -294,7 +302,7 @@
|
|||||||
<DotsHorizontal class="w-4 h-4" />
|
<DotsHorizontal class="w-4 h-4" />
|
||||||
</button>
|
</button>
|
||||||
<ul
|
<ul
|
||||||
class="dropdown-content menu bg-base-100 rounded-box z-[1] w-64 p-2 shadow-xl border border-base-300 mt-1"
|
class="dropdown-content menu bg-base-100 rounded-box z-[60] w-64 p-2 shadow-xl border border-base-300 mt-1"
|
||||||
>
|
>
|
||||||
{#if type != 'viewonly'}
|
{#if type != 'viewonly'}
|
||||||
<li>
|
<li>
|
||||||
@@ -380,8 +388,8 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{:else if user && collection.shared_with && collection.shared_with.includes(user.uuid) && type != 'link'}
|
{:else if isSharedMember && type != 'link'}
|
||||||
<div class="dropdown dropdown-end">
|
<div class="dropdown dropdown-end z-30">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-ghost bg-black/40 backdrop-blur-sm text-white rounded-full w-7 h-7 p-0 min-h-0 border-0 hover:bg-black/55"
|
class="btn btn-ghost bg-black/40 backdrop-blur-sm text-white rounded-full w-7 h-7 p-0 min-h-0 border-0 hover:bg-black/55"
|
||||||
@@ -390,7 +398,7 @@
|
|||||||
<DotsHorizontal class="w-4 h-4" />
|
<DotsHorizontal class="w-4 h-4" />
|
||||||
</button>
|
</button>
|
||||||
<ul
|
<ul
|
||||||
class="dropdown-content menu bg-base-100 rounded-box z-[1] w-64 p-2 shadow-xl border border-base-300 mt-1"
|
class="dropdown-content menu bg-base-100 rounded-box z-[60] w-64 p-2 shadow-xl border border-base-300 mt-1"
|
||||||
>
|
>
|
||||||
<li>
|
<li>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -626,6 +626,7 @@
|
|||||||
"invites": {
|
"invites": {
|
||||||
"accept": "يقبل",
|
"accept": "يقبل",
|
||||||
"accept_failed": "فشل في قبول الدعوة",
|
"accept_failed": "فشل في قبول الدعوة",
|
||||||
|
"fetch_failed": "فشل في جلب الدعوات",
|
||||||
"accepted": "دعوة مقبولة",
|
"accepted": "دعوة مقبولة",
|
||||||
"by": "بواسطة",
|
"by": "بواسطة",
|
||||||
"decline": "انخفاض",
|
"decline": "انخفاض",
|
||||||
@@ -1081,7 +1082,8 @@
|
|||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"show_less": "إخفاء التفاصيل",
|
"show_less": "إخفاء التفاصيل",
|
||||||
"show_more": "عرض المزيد"
|
"show_more": "عرض المزيد",
|
||||||
|
"refresh": "تحديث"
|
||||||
},
|
},
|
||||||
"currencies": {
|
"currencies": {
|
||||||
"AED": "درهم اماراتي",
|
"AED": "درهم اماراتي",
|
||||||
|
|||||||
@@ -1038,6 +1038,7 @@
|
|||||||
"invites": {
|
"invites": {
|
||||||
"accept": "Akzeptieren",
|
"accept": "Akzeptieren",
|
||||||
"accept_failed": "Fehler beim Akzeptieren der Einladung",
|
"accept_failed": "Fehler beim Akzeptieren der Einladung",
|
||||||
|
"fetch_failed": "Einladungen konnten nicht geladen werden",
|
||||||
"accepted": "Einladung akzeptiert",
|
"accepted": "Einladung akzeptiert",
|
||||||
"by": "von",
|
"by": "von",
|
||||||
"decline": "Ablehnen",
|
"decline": "Ablehnen",
|
||||||
@@ -1081,7 +1082,8 @@
|
|||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"show_less": "Details ausblenden",
|
"show_less": "Details ausblenden",
|
||||||
"show_more": "Mehr anzeigen"
|
"show_more": "Mehr anzeigen",
|
||||||
|
"refresh": "Aktualisieren"
|
||||||
},
|
},
|
||||||
"currencies": {
|
"currencies": {
|
||||||
"AED": "VAE-Dirham",
|
"AED": "VAE-Dirham",
|
||||||
|
|||||||
@@ -1040,6 +1040,7 @@
|
|||||||
"invites": {
|
"invites": {
|
||||||
"accepted": "Invite accepted",
|
"accepted": "Invite accepted",
|
||||||
"accept_failed": "Failed to accept invite",
|
"accept_failed": "Failed to accept invite",
|
||||||
|
"fetch_failed": "Failed to fetch invites",
|
||||||
"declined": "Invite declined",
|
"declined": "Invite declined",
|
||||||
"decline_failed": "Failed to decline invite",
|
"decline_failed": "Failed to decline invite",
|
||||||
"title": "Invites",
|
"title": "Invites",
|
||||||
@@ -1103,7 +1104,8 @@
|
|||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"show_less": "Hide details",
|
"show_less": "Hide details",
|
||||||
"show_more": "Show more"
|
"show_more": "Show more",
|
||||||
|
"refresh": "Refresh"
|
||||||
},
|
},
|
||||||
"collections": {
|
"collections": {
|
||||||
"not_found": "Collection Not Found",
|
"not_found": "Collection Not Found",
|
||||||
|
|||||||
@@ -1038,6 +1038,7 @@
|
|||||||
"invites": {
|
"invites": {
|
||||||
"accept": "Aceptar",
|
"accept": "Aceptar",
|
||||||
"accept_failed": "No se pudo aceptar la invitación",
|
"accept_failed": "No se pudo aceptar la invitación",
|
||||||
|
"fetch_failed": "No se pudieron cargar las invitaciones",
|
||||||
"accepted": "Invite aceptado",
|
"accepted": "Invite aceptado",
|
||||||
"by": "por",
|
"by": "por",
|
||||||
"decline": "Rechazar",
|
"decline": "Rechazar",
|
||||||
@@ -1081,7 +1082,8 @@
|
|||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"show_less": "Ocultar detalles",
|
"show_less": "Ocultar detalles",
|
||||||
"show_more": "Mostrar más"
|
"show_more": "Mostrar más",
|
||||||
|
"refresh": "Actualizar"
|
||||||
},
|
},
|
||||||
"currencies": {
|
"currencies": {
|
||||||
"AED": "Dírham de los Emiratos Árabes Unidos",
|
"AED": "Dírham de los Emiratos Árabes Unidos",
|
||||||
|
|||||||
@@ -1037,6 +1037,7 @@
|
|||||||
"settings_download_backup": "Télécharger la sauvegarde",
|
"settings_download_backup": "Télécharger la sauvegarde",
|
||||||
"invites": {
|
"invites": {
|
||||||
"accept_failed": "Échec de l'acceptation de l'invitation",
|
"accept_failed": "Échec de l'acceptation de l'invitation",
|
||||||
|
"fetch_failed": "Impossible de récupérer les invitations",
|
||||||
"accepted": "Inviter accepté",
|
"accepted": "Inviter accepté",
|
||||||
"by": "par",
|
"by": "par",
|
||||||
"decline": "Déclin",
|
"decline": "Déclin",
|
||||||
@@ -1081,7 +1082,8 @@
|
|||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"show_less": "Masquer les détails",
|
"show_less": "Masquer les détails",
|
||||||
"show_more": "Afficher plus"
|
"show_more": "Afficher plus",
|
||||||
|
"refresh": "Actualiser"
|
||||||
},
|
},
|
||||||
"currencies": {
|
"currencies": {
|
||||||
"AED": "Dirham des Émirats Arabes Unis",
|
"AED": "Dirham des Émirats Arabes Unis",
|
||||||
|
|||||||
@@ -1038,6 +1038,7 @@
|
|||||||
"invites": {
|
"invites": {
|
||||||
"accepted": "Meghívó elfogadva",
|
"accepted": "Meghívó elfogadva",
|
||||||
"accept_failed": "Nem sikerült elfogadni a meghívót",
|
"accept_failed": "Nem sikerült elfogadni a meghívót",
|
||||||
|
"fetch_failed": "Nem sikerült lekérni a meghívókat",
|
||||||
"declined": "Meghívó elutasítva",
|
"declined": "Meghívó elutasítva",
|
||||||
"decline_failed": "Nem sikerült elutasítani a meghívót",
|
"decline_failed": "Nem sikerült elutasítani a meghívót",
|
||||||
"title": "Meghívók",
|
"title": "Meghívók",
|
||||||
@@ -1081,7 +1082,8 @@
|
|||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"show_less": "Részletek elrejtése",
|
"show_less": "Részletek elrejtése",
|
||||||
"show_more": "Mutasson többet"
|
"show_more": "Mutasson többet",
|
||||||
|
"refresh": "Frissítés"
|
||||||
},
|
},
|
||||||
"currencies": {
|
"currencies": {
|
||||||
"AED": "Egyesült Arab Emírségek dirham",
|
"AED": "Egyesült Arab Emírségek dirham",
|
||||||
|
|||||||
@@ -1038,6 +1038,7 @@
|
|||||||
"invites": {
|
"invites": {
|
||||||
"accept": "Accettare",
|
"accept": "Accettare",
|
||||||
"accept_failed": "Impossibile accettare l'invito",
|
"accept_failed": "Impossibile accettare l'invito",
|
||||||
|
"fetch_failed": "Impossibile recuperare gli inviti",
|
||||||
"accepted": "Invito accettato",
|
"accepted": "Invito accettato",
|
||||||
"by": "di",
|
"by": "di",
|
||||||
"decline": "Declino",
|
"decline": "Declino",
|
||||||
@@ -1081,7 +1082,8 @@
|
|||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"show_less": "Nascondi dettagli",
|
"show_less": "Nascondi dettagli",
|
||||||
"show_more": "Mostra di più"
|
"show_more": "Mostra di più",
|
||||||
|
"refresh": "Aggiorna"
|
||||||
},
|
},
|
||||||
"currencies": {
|
"currencies": {
|
||||||
"AED": "Dirham degli Emirati Arabi Uniti",
|
"AED": "Dirham degli Emirati Arabi Uniti",
|
||||||
|
|||||||
@@ -626,6 +626,7 @@
|
|||||||
"invites": {
|
"invites": {
|
||||||
"accept": "受け入れる",
|
"accept": "受け入れる",
|
||||||
"accept_failed": "招待を受け入れなかった",
|
"accept_failed": "招待を受け入れなかった",
|
||||||
|
"fetch_failed": "招待を取得できませんでした",
|
||||||
"accepted": "招待された招待",
|
"accepted": "招待された招待",
|
||||||
"by": "による",
|
"by": "による",
|
||||||
"decline": "衰退",
|
"decline": "衰退",
|
||||||
@@ -1081,7 +1082,8 @@
|
|||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"show_less": "詳細を隠す",
|
"show_less": "詳細を隠す",
|
||||||
"show_more": "もっと見る"
|
"show_more": "もっと見る",
|
||||||
|
"refresh": "更新"
|
||||||
},
|
},
|
||||||
"currencies": {
|
"currencies": {
|
||||||
"AED": "アラブ首長国連邦ディルハム",
|
"AED": "アラブ首長国連邦ディルハム",
|
||||||
|
|||||||
@@ -1038,6 +1038,7 @@
|
|||||||
"invites": {
|
"invites": {
|
||||||
"accept": "수용하다",
|
"accept": "수용하다",
|
||||||
"accept_failed": "초대를 수락하지 못했습니다",
|
"accept_failed": "초대를 수락하지 못했습니다",
|
||||||
|
"fetch_failed": "초대를 불러오지 못했습니다",
|
||||||
"accepted": "허가를 초대하십시오",
|
"accepted": "허가를 초대하십시오",
|
||||||
"by": "~에 의해",
|
"by": "~에 의해",
|
||||||
"decline": "감소",
|
"decline": "감소",
|
||||||
@@ -1081,7 +1082,8 @@
|
|||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"show_less": "세부정보 숨기기",
|
"show_less": "세부정보 숨기기",
|
||||||
"show_more": "더 보기"
|
"show_more": "더 보기",
|
||||||
|
"refresh": "새로고침"
|
||||||
},
|
},
|
||||||
"currencies": {
|
"currencies": {
|
||||||
"AED": "UAE 디르함",
|
"AED": "UAE 디르함",
|
||||||
|
|||||||
@@ -1038,6 +1038,7 @@
|
|||||||
"invites": {
|
"invites": {
|
||||||
"accept": "Accepteren",
|
"accept": "Accepteren",
|
||||||
"accept_failed": "Kan uitnodigen niet accepteren",
|
"accept_failed": "Kan uitnodigen niet accepteren",
|
||||||
|
"fetch_failed": "Uitnodigingen konden niet worden opgehaald",
|
||||||
"accepted": "Nodig geaccepteerd uit",
|
"accepted": "Nodig geaccepteerd uit",
|
||||||
"by": "door",
|
"by": "door",
|
||||||
"decline": "Afwijzen",
|
"decline": "Afwijzen",
|
||||||
@@ -1081,7 +1082,8 @@
|
|||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"show_less": "Details verbergen",
|
"show_less": "Details verbergen",
|
||||||
"show_more": "Laat meer zien"
|
"show_more": "Laat meer zien",
|
||||||
|
"refresh": "Vernieuwen"
|
||||||
},
|
},
|
||||||
"currencies": {
|
"currencies": {
|
||||||
"AED": "VAE Dirham",
|
"AED": "VAE Dirham",
|
||||||
|
|||||||
@@ -1038,6 +1038,7 @@
|
|||||||
"invites": {
|
"invites": {
|
||||||
"accept": "Akseptere",
|
"accept": "Akseptere",
|
||||||
"accept_failed": "Kunne ikke godta invitasjon",
|
"accept_failed": "Kunne ikke godta invitasjon",
|
||||||
|
"fetch_failed": "Kunne ikke hente invitasjoner",
|
||||||
"accepted": "Inviter akseptert",
|
"accepted": "Inviter akseptert",
|
||||||
"by": "ved",
|
"by": "ved",
|
||||||
"decline": "Avslå",
|
"decline": "Avslå",
|
||||||
@@ -1081,7 +1082,8 @@
|
|||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"show_less": "Skjul detaljer",
|
"show_less": "Skjul detaljer",
|
||||||
"show_more": "Vis mer"
|
"show_more": "Vis mer",
|
||||||
|
"refresh": "Oppdater"
|
||||||
},
|
},
|
||||||
"currencies": {
|
"currencies": {
|
||||||
"AED": "UAE Dirham",
|
"AED": "UAE Dirham",
|
||||||
|
|||||||
@@ -1038,6 +1038,7 @@
|
|||||||
"invites": {
|
"invites": {
|
||||||
"accept": "Przyjąć",
|
"accept": "Przyjąć",
|
||||||
"accept_failed": "Nie udało się zaakceptować zaproszenia",
|
"accept_failed": "Nie udało się zaakceptować zaproszenia",
|
||||||
|
"fetch_failed": "Nie udało się pobrać zaproszeń",
|
||||||
"accepted": "Zaproś zaakceptowane",
|
"accepted": "Zaproś zaakceptowane",
|
||||||
"by": "przez",
|
"by": "przez",
|
||||||
"decline": "Spadek",
|
"decline": "Spadek",
|
||||||
@@ -1081,7 +1082,8 @@
|
|||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"show_less": "Ukryj szczegóły",
|
"show_less": "Ukryj szczegóły",
|
||||||
"show_more": "Pokaż więcej"
|
"show_more": "Pokaż więcej",
|
||||||
|
"refresh": "Odśwież"
|
||||||
},
|
},
|
||||||
"currencies": {
|
"currencies": {
|
||||||
"AED": "Dirham Zjednoczonych Emiratów Arabskich",
|
"AED": "Dirham Zjednoczonych Emiratów Arabskich",
|
||||||
|
|||||||
@@ -626,6 +626,7 @@
|
|||||||
"invites": {
|
"invites": {
|
||||||
"accept": "Aceitar",
|
"accept": "Aceitar",
|
||||||
"accept_failed": "Falha ao aceitar convite",
|
"accept_failed": "Falha ao aceitar convite",
|
||||||
|
"fetch_failed": "Falha ao buscar convites",
|
||||||
"accepted": "Convite Aceito",
|
"accepted": "Convite Aceito",
|
||||||
"by": "por",
|
"by": "por",
|
||||||
"decline": "Recusar",
|
"decline": "Recusar",
|
||||||
@@ -1081,7 +1082,8 @@
|
|||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"show_less": "Ocultar detalhes",
|
"show_less": "Ocultar detalhes",
|
||||||
"show_more": "Mostrar mais"
|
"show_more": "Mostrar mais",
|
||||||
|
"refresh": "Atualizar"
|
||||||
},
|
},
|
||||||
"currencies": {
|
"currencies": {
|
||||||
"AED": "Dirham dos Emirados Árabes Unidos",
|
"AED": "Dirham dos Emirados Árabes Unidos",
|
||||||
|
|||||||
@@ -618,7 +618,8 @@
|
|||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"show_less": "Ascunde detaliile",
|
"show_less": "Ascunde detaliile",
|
||||||
"show_more": "Arată mai multe"
|
"show_more": "Arată mai multe",
|
||||||
|
"refresh": "Reîmprospătează"
|
||||||
},
|
},
|
||||||
"currencies": {
|
"currencies": {
|
||||||
"AED": "Dirhamul Emiratelor Arabe Unite",
|
"AED": "Dirhamul Emiratelor Arabe Unite",
|
||||||
@@ -702,6 +703,7 @@
|
|||||||
"invites": {
|
"invites": {
|
||||||
"accept": "Accepta",
|
"accept": "Accepta",
|
||||||
"accept_failed": "Nu s-a acceptat invitația",
|
"accept_failed": "Nu s-a acceptat invitația",
|
||||||
|
"fetch_failed": "Nu s-au putut încărca invitațiile",
|
||||||
"accepted": "Invitația a fost acceptată",
|
"accepted": "Invitația a fost acceptată",
|
||||||
"by": "de",
|
"by": "de",
|
||||||
"decline": "Declin",
|
"decline": "Declin",
|
||||||
|
|||||||
@@ -1038,6 +1038,7 @@
|
|||||||
"invites": {
|
"invites": {
|
||||||
"accept": "Принять",
|
"accept": "Принять",
|
||||||
"accept_failed": "Не удалось принять приглашение",
|
"accept_failed": "Не удалось принять приглашение",
|
||||||
|
"fetch_failed": "Не удалось загрузить приглашения",
|
||||||
"accepted": "Приглашение принято",
|
"accepted": "Приглашение принято",
|
||||||
"by": "к",
|
"by": "к",
|
||||||
"decline": "Отклонить",
|
"decline": "Отклонить",
|
||||||
@@ -1081,7 +1082,8 @@
|
|||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"show_less": "Скрыть детали",
|
"show_less": "Скрыть детали",
|
||||||
"show_more": "Показать больше"
|
"show_more": "Показать больше",
|
||||||
|
"refresh": "Обновить"
|
||||||
},
|
},
|
||||||
"currencies": {
|
"currencies": {
|
||||||
"AED": "Дирхам ОАЭ",
|
"AED": "Дирхам ОАЭ",
|
||||||
|
|||||||
@@ -1038,6 +1038,7 @@
|
|||||||
"invites": {
|
"invites": {
|
||||||
"accepted": "Pozvánka prijatá",
|
"accepted": "Pozvánka prijatá",
|
||||||
"accept_failed": "Nepodarilo sa prijať pozvánku",
|
"accept_failed": "Nepodarilo sa prijať pozvánku",
|
||||||
|
"fetch_failed": "Nepodarilo sa načítať pozvánky",
|
||||||
"declined": "Pozvánka zamietnutá",
|
"declined": "Pozvánka zamietnutá",
|
||||||
"decline_failed": "Nepodarilo sa zamietnuť pozvánku",
|
"decline_failed": "Nepodarilo sa zamietnuť pozvánku",
|
||||||
"title": "Pozvánky",
|
"title": "Pozvánky",
|
||||||
@@ -1081,7 +1082,8 @@
|
|||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"show_less": "Skryť podrobnosti",
|
"show_less": "Skryť podrobnosti",
|
||||||
"show_more": "Ukáž viac"
|
"show_more": "Ukáž viac",
|
||||||
|
"refresh": "Obnoviť"
|
||||||
},
|
},
|
||||||
"currencies": {
|
"currencies": {
|
||||||
"AED": "Dirham SAE",
|
"AED": "Dirham SAE",
|
||||||
|
|||||||
@@ -1038,6 +1038,7 @@
|
|||||||
"invites": {
|
"invites": {
|
||||||
"accept": "Acceptera",
|
"accept": "Acceptera",
|
||||||
"accept_failed": "Det gick inte att acceptera inbjudan",
|
"accept_failed": "Det gick inte att acceptera inbjudan",
|
||||||
|
"fetch_failed": "Det gick inte att hämta inbjudningar",
|
||||||
"accepted": "Bjuda in accepterad",
|
"accepted": "Bjuda in accepterad",
|
||||||
"by": "av",
|
"by": "av",
|
||||||
"decline": "Nedgång",
|
"decline": "Nedgång",
|
||||||
@@ -1081,7 +1082,8 @@
|
|||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"show_less": "Dölj detaljer",
|
"show_less": "Dölj detaljer",
|
||||||
"show_more": "Visa mer"
|
"show_more": "Visa mer",
|
||||||
|
"refresh": "Uppdatera"
|
||||||
},
|
},
|
||||||
"currencies": {
|
"currencies": {
|
||||||
"AED": "UAE Dirham",
|
"AED": "UAE Dirham",
|
||||||
|
|||||||
@@ -1038,6 +1038,7 @@
|
|||||||
"invites": {
|
"invites": {
|
||||||
"accepted": "Davet kabul edildi",
|
"accepted": "Davet kabul edildi",
|
||||||
"accept_failed": "Davet kabul edilemedi",
|
"accept_failed": "Davet kabul edilemedi",
|
||||||
|
"fetch_failed": "Davetler alınamadı",
|
||||||
"declined": "Davet reddedildi",
|
"declined": "Davet reddedildi",
|
||||||
"decline_failed": "Davet reddedilemedi",
|
"decline_failed": "Davet reddedilemedi",
|
||||||
"title": "Davetler",
|
"title": "Davetler",
|
||||||
@@ -1081,7 +1082,8 @@
|
|||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"show_less": "Ayrıntıları gizle",
|
"show_less": "Ayrıntıları gizle",
|
||||||
"show_more": "Daha fazlasını göster"
|
"show_more": "Daha fazlasını göster",
|
||||||
|
"refresh": "Yenile"
|
||||||
},
|
},
|
||||||
"currencies": {
|
"currencies": {
|
||||||
"AED": "BAE Dirhemi",
|
"AED": "BAE Dirhemi",
|
||||||
|
|||||||
@@ -626,6 +626,7 @@
|
|||||||
"invites": {
|
"invites": {
|
||||||
"accept": "прийняти",
|
"accept": "прийняти",
|
||||||
"accept_failed": "Не вдалося прийняти запрошення",
|
"accept_failed": "Не вдалося прийняти запрошення",
|
||||||
|
"fetch_failed": "Не вдалося завантажити запрошення",
|
||||||
"accepted": "Запрошення прийнято",
|
"accepted": "Запрошення прийнято",
|
||||||
"by": "за",
|
"by": "за",
|
||||||
"decline": "відхилити",
|
"decline": "відхилити",
|
||||||
@@ -1081,7 +1082,8 @@
|
|||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"show_less": "Приховати деталі",
|
"show_less": "Приховати деталі",
|
||||||
"show_more": "Показати більше"
|
"show_more": "Показати більше",
|
||||||
|
"refresh": "Оновити"
|
||||||
},
|
},
|
||||||
"currencies": {
|
"currencies": {
|
||||||
"AED": "дирхам ОАЕ",
|
"AED": "дирхам ОАЕ",
|
||||||
|
|||||||
@@ -1038,6 +1038,7 @@
|
|||||||
"invites": {
|
"invites": {
|
||||||
"accept": "接受",
|
"accept": "接受",
|
||||||
"accept_failed": "未能接受邀请",
|
"accept_failed": "未能接受邀请",
|
||||||
|
"fetch_failed": "无法获取邀请",
|
||||||
"accepted": "邀请接受",
|
"accepted": "邀请接受",
|
||||||
"by": "经过",
|
"by": "经过",
|
||||||
"decline": "衰退",
|
"decline": "衰退",
|
||||||
@@ -1066,7 +1067,8 @@
|
|||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"show_less": "隐藏详细信息",
|
"show_less": "隐藏详细信息",
|
||||||
"show_more": "显示更多"
|
"show_more": "显示更多",
|
||||||
|
"refresh": "刷新"
|
||||||
},
|
},
|
||||||
"itinerary": {
|
"itinerary": {
|
||||||
"item_remove_error": "从行程中删除项目时出错",
|
"item_remove_error": "从行程中删除项目时出错",
|
||||||
|
|||||||
@@ -4,18 +4,14 @@
|
|||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import CollectionCard from '$lib/components/cards/CollectionCard.svelte';
|
import CollectionCard from '$lib/components/cards/CollectionCard.svelte';
|
||||||
import CollectionModal from '$lib/components/CollectionModal.svelte';
|
import CollectionModal from '$lib/components/CollectionModal.svelte';
|
||||||
import type { Collection, CollectionInvite, SlimCollection } from '$lib/types';
|
import type { Collection, SlimCollection } from '$lib/types';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
import Plus from '~icons/mdi/plus';
|
import Plus from '~icons/mdi/plus';
|
||||||
import Filter from '~icons/mdi/filter-variant';
|
import Filter from '~icons/mdi/filter-variant';
|
||||||
import Sort from '~icons/mdi/sort';
|
import Sort from '~icons/mdi/sort';
|
||||||
import Archive from '~icons/mdi/archive';
|
import Archive from '~icons/mdi/archive';
|
||||||
import Share from '~icons/mdi/share-variant';
|
|
||||||
import CollectionIcon from '~icons/mdi/folder-multiple';
|
import CollectionIcon from '~icons/mdi/folder-multiple';
|
||||||
import MailIcon from '~icons/mdi/email';
|
|
||||||
import CheckIcon from '~icons/mdi/check';
|
|
||||||
import CloseIcon from '~icons/mdi/close';
|
|
||||||
import { addToast } from '$lib/toasts';
|
import { addToast } from '$lib/toasts';
|
||||||
import DeleteWarning from '$lib/components/DeleteWarning.svelte';
|
import DeleteWarning from '$lib/components/DeleteWarning.svelte';
|
||||||
|
|
||||||
@@ -28,7 +24,7 @@
|
|||||||
let newType: string = '';
|
let newType: string = '';
|
||||||
let resultsPerPage: number = 25;
|
let resultsPerPage: number = 25;
|
||||||
let isShowingCollectionModal: boolean = false;
|
let isShowingCollectionModal: boolean = false;
|
||||||
let activeView: 'owned' | 'shared' | 'archived' | 'invites' = 'owned';
|
let activeView: 'collections' | 'archived' = 'collections';
|
||||||
|
|
||||||
let next: string | null = data.props.next || null;
|
let next: string | null = data.props.next || null;
|
||||||
let previous: string | null = data.props.previous || null;
|
let previous: string | null = data.props.previous || null;
|
||||||
@@ -39,35 +35,19 @@
|
|||||||
let orderDirection = data.props.order_direction || 'asc';
|
let orderDirection = data.props.order_direction || 'asc';
|
||||||
let statusFilter = data.props.status || '';
|
let statusFilter = data.props.status || '';
|
||||||
|
|
||||||
let invites: CollectionInvite[] = data.props.invites || [];
|
|
||||||
|
|
||||||
let sidebarOpen = false;
|
let sidebarOpen = false;
|
||||||
let collectionToEdit: Collection | null = null;
|
let collectionToEdit: Collection | null = null;
|
||||||
|
|
||||||
$: currentCollections =
|
$: mergedCollections = [...collections, ...sharedCollections].filter(
|
||||||
activeView === 'owned'
|
(collection, index, list) => index === list.findIndex((entry) => entry.id === collection.id)
|
||||||
? collections
|
);
|
||||||
: activeView === 'shared'
|
|
||||||
? sharedCollections
|
|
||||||
: activeView === 'archived'
|
|
||||||
? archivedCollections
|
|
||||||
: [];
|
|
||||||
|
|
||||||
$: currentCount =
|
$: currentCollections = activeView === 'collections' ? mergedCollections : archivedCollections;
|
||||||
activeView === 'owned'
|
|
||||||
? collections.length
|
|
||||||
: activeView === 'shared'
|
|
||||||
? sharedCollections.length
|
|
||||||
: activeView === 'archived'
|
|
||||||
? archivedCollections.length
|
|
||||||
: activeView === 'invites'
|
|
||||||
? invites.length
|
|
||||||
: 0;
|
|
||||||
|
|
||||||
// Optionally, keep count in sync with collections only for owned view
|
// Keep count in sync with collections view
|
||||||
$: {
|
$: {
|
||||||
if (activeView === 'owned' && count !== collections.length) {
|
if (activeView === 'collections' && count !== mergedCollections.length) {
|
||||||
count = collections.length;
|
count = mergedCollections.length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,7 +180,7 @@
|
|||||||
(collection) => collection.id !== duplicatedCollection.id
|
(collection) => collection.id !== duplicatedCollection.id
|
||||||
);
|
);
|
||||||
|
|
||||||
activeView = 'owned';
|
activeView = 'collections';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function editCollection(event: CustomEvent<SlimCollection>) {
|
async function editCollection(event: CustomEvent<SlimCollection>) {
|
||||||
@@ -252,86 +232,9 @@
|
|||||||
sidebarOpen = !sidebarOpen;
|
sidebarOpen = !sidebarOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
function switchView(view: 'owned' | 'shared' | 'archived' | 'invites') {
|
function switchView(view: 'collections' | 'archived') {
|
||||||
activeView = view;
|
activeView = view;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invite functions
|
|
||||||
async function acceptInvite(invite: CollectionInvite) {
|
|
||||||
try {
|
|
||||||
const res = await fetch(`/api/collections/${invite.collection}/accept-invite/`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res.ok) {
|
|
||||||
// Try to parse returned collection data
|
|
||||||
let data: any = null;
|
|
||||||
try {
|
|
||||||
data = await res.json();
|
|
||||||
} catch (e) {
|
|
||||||
data = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove invite from list
|
|
||||||
invites = invites.filter((i) => i.id !== invite.id);
|
|
||||||
addToast('success', `${$t('invites.accepted')} "${invite.name}"`);
|
|
||||||
|
|
||||||
// If API returned the accepted collection, add it to sharedCollections immediately
|
|
||||||
if (data && (data.collection || data.result || data.id)) {
|
|
||||||
// Normalize expected shapes: {collection: {...}} or collection object directly
|
|
||||||
const newCollection = data.collection ? data.collection : data;
|
|
||||||
// Prepend so it's visible at top
|
|
||||||
sharedCollections = [newCollection as SlimCollection, ...sharedCollections];
|
|
||||||
} else {
|
|
||||||
// Fallback: refresh shared collections from API
|
|
||||||
try {
|
|
||||||
const sharedRes = await fetch(`/api/collections/shared/?nested=true`);
|
|
||||||
if (sharedRes.ok) {
|
|
||||||
const sharedData = await sharedRes.json();
|
|
||||||
// Prefer results if paginated
|
|
||||||
sharedCollections = sharedData.results ? sharedData.results : sharedData;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
// ignore fallback errors; user already got success toast
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const error = await res.json();
|
|
||||||
addToast('error', error.error || $t('invites.accept_failed'));
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
addToast('error', $t('invites.accept_failed'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function declineInvite(invite: CollectionInvite) {
|
|
||||||
try {
|
|
||||||
const res = await fetch(`/api/collections/${invite.collection}/decline-invite/`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res.ok) {
|
|
||||||
// Remove invite from list
|
|
||||||
invites = invites.filter((i) => i.id !== invite.id);
|
|
||||||
addToast('success', `${$t('invites.declined')} "${invite.name}"`);
|
|
||||||
} else {
|
|
||||||
const error = await res.json();
|
|
||||||
addToast('error', error.error || $t('invites.decline_failed'));
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
addToast('error', $t('invites.decline_failed'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatDate(dateString: string): string {
|
|
||||||
return new Date(dateString).toLocaleDateString('en-GB');
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
@@ -406,25 +309,14 @@
|
|||||||
<div class="flex border-b border-base-200 mt-4 overflow-x-auto">
|
<div class="flex border-b border-base-200 mt-4 overflow-x-auto">
|
||||||
<button
|
<button
|
||||||
class="tab px-4 py-2 text-sm font-medium border-b-2 transition-colors whitespace-nowrap {activeView ===
|
class="tab px-4 py-2 text-sm font-medium border-b-2 transition-colors whitespace-nowrap {activeView ===
|
||||||
'owned'
|
'collections'
|
||||||
? 'border-primary text-primary'
|
? 'border-primary text-primary'
|
||||||
: 'border-transparent text-base-content/60 hover:text-base-content'}"
|
: 'border-transparent text-base-content/60 hover:text-base-content'}"
|
||||||
on:click={() => switchView('owned')}
|
on:click={() => switchView('collections')}
|
||||||
>
|
>
|
||||||
<CollectionIcon class="w-4 h-4" />
|
<CollectionIcon class="w-4 h-4" />
|
||||||
<span class="hidden sm:inline">{$t('adventures.my_collections')}</span>
|
<span class="hidden sm:inline">{$t('navbar.collections')}</span>
|
||||||
<div class="badge badge-sm badge-ghost">{collections.length}</div>
|
<div class="badge badge-sm badge-ghost">{mergedCollections.length}</div>
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="tab px-4 py-2 text-sm font-medium border-b-2 transition-colors whitespace-nowrap {activeView ===
|
|
||||||
'shared'
|
|
||||||
? 'border-primary text-primary'
|
|
||||||
: 'border-transparent text-base-content/60 hover:text-base-content'}"
|
|
||||||
on:click={() => switchView('shared')}
|
|
||||||
>
|
|
||||||
<Share class="w-4 h-4" />
|
|
||||||
<span class="hidden sm:inline">{$t('share.shared')}</span>
|
|
||||||
<div class="badge badge-sm badge-ghost">{sharedCollections.length}</div>
|
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="tab px-4 py-2 text-sm font-medium border-b-2 transition-colors whitespace-nowrap {activeView ===
|
class="tab px-4 py-2 text-sm font-medium border-b-2 transition-colors whitespace-nowrap {activeView ===
|
||||||
@@ -437,121 +329,33 @@
|
|||||||
<span class="hidden sm:inline">{$t('adventures.archived')}</span>
|
<span class="hidden sm:inline">{$t('adventures.archived')}</span>
|
||||||
<div class="badge badge-sm badge-ghost">{archivedCollections.length}</div>
|
<div class="badge badge-sm badge-ghost">{archivedCollections.length}</div>
|
||||||
</button>
|
</button>
|
||||||
<button
|
|
||||||
class="tab px-4 py-2 text-sm font-medium border-b-2 transition-colors whitespace-nowrap {activeView ===
|
|
||||||
'invites'
|
|
||||||
? 'border-primary text-primary'
|
|
||||||
: 'border-transparent text-base-content/60 hover:text-base-content'}"
|
|
||||||
on:click={() => switchView('invites')}
|
|
||||||
>
|
|
||||||
<div class="indicator">
|
|
||||||
<MailIcon class="w-4 h-4" />
|
|
||||||
{#if invites.length > 0}
|
|
||||||
<span class="indicator-item badge badge-xs badge-error"></span>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
<span class="hidden sm:inline">{$t('invites.title')}</span>
|
|
||||||
<div class="badge badge-sm {invites.length > 0 ? 'badge-error' : 'badge-ghost'}">
|
|
||||||
{invites.length}
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
<div class="container mx-auto px-6 py-8">
|
<div class="container mx-auto px-6 py-8">
|
||||||
{#if activeView === 'invites'}
|
{#if currentCollections.length === 0}
|
||||||
<!-- Invites Content -->
|
|
||||||
{#if invites.length === 0}
|
|
||||||
<div class="flex flex-col items-center justify-center py-16">
|
|
||||||
<div class="p-6 bg-base-200/50 rounded-2xl mb-6">
|
|
||||||
<MailIcon class="w-16 h-16 text-base-content/30" />
|
|
||||||
</div>
|
|
||||||
<h3 class="text-xl font-semibold text-base-content/70 mb-2">
|
|
||||||
{$t('invites.no_invites')}
|
|
||||||
</h3>
|
|
||||||
<p class="text-base-content/50 text-center max-w-md">
|
|
||||||
{$t('invites.no_invites_desc')}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
{:else}
|
|
||||||
<div class="space-y-4">
|
|
||||||
{#each invites as invite}
|
|
||||||
<div
|
|
||||||
class="card bg-base-100 shadow-lg border border-base-300 hover:shadow-xl transition-shadow"
|
|
||||||
>
|
|
||||||
<div class="card-body p-6">
|
|
||||||
<div class="flex items-start justify-between">
|
|
||||||
<div class="flex-1">
|
|
||||||
<div class="flex items-center gap-3 mb-2">
|
|
||||||
<div class="p-2 bg-primary/10 rounded-lg">
|
|
||||||
<CollectionIcon class="w-5 h-5 text-primary" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h3 class="font-semibold text-lg">
|
|
||||||
{invite.name}
|
|
||||||
</h3>
|
|
||||||
<p class="text-xs text-base-content/50">
|
|
||||||
{$t('invites.invited_on')}
|
|
||||||
{formatDate(invite.created_at)}
|
|
||||||
{$t('invites.by')}
|
|
||||||
{invite.collection_owner_username || ''}
|
|
||||||
({invite.collection_user_first_name || ''}
|
|
||||||
{invite.collection_user_last_name || ''})
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-2 ml-4">
|
|
||||||
<button
|
|
||||||
class="btn btn-success btn-sm gap-2"
|
|
||||||
on:click={() => acceptInvite(invite)}
|
|
||||||
>
|
|
||||||
<CheckIcon class="w-4 h-4" />
|
|
||||||
{$t('invites.accept')}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="btn btn-error btn-sm btn-outline gap-2"
|
|
||||||
on:click={() => declineInvite(invite)}
|
|
||||||
>
|
|
||||||
<CloseIcon class="w-4 h-4" />
|
|
||||||
{$t('invites.decline')}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{:else if currentCollections.length === 0}
|
|
||||||
<!-- Empty State for Collections -->
|
<!-- Empty State for Collections -->
|
||||||
<div class="flex flex-col items-center justify-center py-16">
|
<div class="flex flex-col items-center justify-center py-16">
|
||||||
<div class="p-6 bg-base-200/50 rounded-2xl mb-6">
|
<div class="p-6 bg-base-200/50 rounded-2xl mb-6">
|
||||||
{#if activeView === 'owned'}
|
{#if activeView === 'collections'}
|
||||||
<CollectionIcon class="w-16 h-16 text-base-content/30" />
|
<CollectionIcon class="w-16 h-16 text-base-content/30" />
|
||||||
{:else if activeView === 'shared'}
|
|
||||||
<Share class="w-16 h-16 text-base-content/30" />
|
|
||||||
{:else}
|
{:else}
|
||||||
<Archive class="w-16 h-16 text-base-content/30" />
|
<Archive class="w-16 h-16 text-base-content/30" />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<h3 class="text-xl font-semibold text-base-content/70 mb-2">
|
<h3 class="text-xl font-semibold text-base-content/70 mb-2">
|
||||||
{activeView === 'owned'
|
{activeView === 'collections'
|
||||||
? $t('collection.no_collections_yet')
|
? $t('collection.no_collections_yet')
|
||||||
: activeView === 'shared'
|
|
||||||
? $t('collection.no_shared_collections')
|
|
||||||
: $t('collection.no_archived_collections')}
|
: $t('collection.no_archived_collections')}
|
||||||
</h3>
|
</h3>
|
||||||
<p class="text-base-content/50 text-center max-w-md">
|
<p class="text-base-content/50 text-center max-w-md">
|
||||||
{activeView === 'owned'
|
{activeView === 'collections'
|
||||||
? $t('collection.create_first')
|
? $t('collection.create_first')
|
||||||
: activeView === 'shared'
|
|
||||||
? $t('collection.make_sure_public')
|
|
||||||
: $t('collection.archived_appear_here')}
|
: $t('collection.archived_appear_here')}
|
||||||
</p>
|
</p>
|
||||||
{#if activeView === 'owned'}
|
{#if activeView === 'collections'}
|
||||||
<button
|
<button
|
||||||
class="btn btn-primary btn-wide mt-6 gap-2"
|
class="btn btn-primary btn-wide mt-6 gap-2"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
@@ -587,7 +391,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Pagination -->
|
<!-- Pagination -->
|
||||||
{#if activeView === 'owned' && (next || previous)}
|
{#if activeView === 'collections' && (next || previous)}
|
||||||
<div class="flex justify-center mt-12">
|
<div class="flex justify-center mt-12">
|
||||||
<div class="join bg-base-100 shadow-lg rounded-2xl p-2">
|
<div class="join bg-base-100 shadow-lg rounded-2xl p-2">
|
||||||
{#each Array.from({ length: totalPages }, (_, i) => i + 1) as page}
|
{#each Array.from({ length: totalPages }, (_, i) => i + 1) as page}
|
||||||
@@ -620,10 +424,8 @@
|
|||||||
<h2 class="text-xl font-bold">{$t('adventures.filters_and_sort')}</h2>
|
<h2 class="text-xl font-bold">{$t('adventures.filters_and_sort')}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Only show sort options for collection views, not invites -->
|
<!-- Status Filter -->
|
||||||
{#if activeView !== 'invites'}
|
<div class="card bg-base-200/50 p-4 mb-4">
|
||||||
<!-- Status Filter -->
|
|
||||||
<div class="card bg-base-200/50 p-4 mb-4">
|
|
||||||
<h3 class="font-semibold text-lg mb-4 flex items-center gap-2">
|
<h3 class="font-semibold text-lg mb-4 flex items-center gap-2">
|
||||||
<Filter class="w-5 h-5" />
|
<Filter class="w-5 h-5" />
|
||||||
{$t('adventures.status_filter')}
|
{$t('adventures.status_filter')}
|
||||||
@@ -681,10 +483,10 @@
|
|||||||
<span class="label-text">✓ {$t('adventures.completed')}</span>
|
<span class="label-text">✓ {$t('adventures.completed')}</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Sort Form - Updated to use URL navigation -->
|
<!-- Sort Form - Updated to use URL navigation -->
|
||||||
<div class="card bg-base-200/50 p-4">
|
<div class="card bg-base-200/50 p-4">
|
||||||
<h3 class="font-semibold text-lg mb-4 flex items-center gap-2">
|
<h3 class="font-semibold text-lg mb-4 flex items-center gap-2">
|
||||||
<Sort class="w-5 h-5" />
|
<Sort class="w-5 h-5" />
|
||||||
{$t(`adventures.sort`)}
|
{$t(`adventures.sort`)}
|
||||||
@@ -755,15 +557,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Floating Action Button -->
|
<!-- Floating Action Button -->
|
||||||
{#if activeView === 'owned'}
|
{#if activeView === 'collections'}
|
||||||
<div class="fixed bottom-6 right-6 z-50">
|
<div class="fixed bottom-6 right-6 z-50">
|
||||||
<div class="dropdown dropdown-top dropdown-end">
|
<div class="dropdown dropdown-top dropdown-end">
|
||||||
<div
|
<div
|
||||||
|
|||||||
Reference in New Issue
Block a user