🔥 Make Photos page completely dynamic with filters
- The page now reacts properly with default Select options (`default` was used to set current instead of `selected`) - Make `filtered` variable reactive from filterCountry/filterSort - Reset link goes to parameters and not just `/photos` - Show latest updated date from first photo of the `photos` data - Display the total of photo depending on the country (calculated from `__layout`)
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/stores'
|
import { page } from '$app/stores'
|
||||||
|
import { browser } from '$app/env'
|
||||||
import { goto } from '$app/navigation'
|
import { goto } from '$app/navigation'
|
||||||
import { getContext } from 'svelte'
|
import { getContext } from 'svelte'
|
||||||
import { fly } from 'svelte/transition'
|
import { fly } from 'svelte/transition'
|
||||||
@@ -18,7 +19,6 @@
|
|||||||
import Newsletter from '$components/organisms/Newsletter.svelte'
|
import Newsletter from '$components/organisms/Newsletter.svelte'
|
||||||
|
|
||||||
export let photos: any[]
|
export let photos: any[]
|
||||||
export let lastUpdated: string
|
|
||||||
export let totalPhotos: number
|
export let totalPhotos: number
|
||||||
export let filteredCountryExists: boolean
|
export let filteredCountryExists: boolean
|
||||||
|
|
||||||
@@ -31,10 +31,13 @@
|
|||||||
|
|
||||||
// Filters
|
// Filters
|
||||||
const urlFiltersParams = new URLSearchParams()
|
const urlFiltersParams = new URLSearchParams()
|
||||||
let filtered: boolean = false
|
let filtered: boolean
|
||||||
let filterCountry: any = $page.query.get('country') || defaultCountry
|
let filterCountry: any = $page.query.get('country') || defaultCountry
|
||||||
let filterSort: string = $page.query.get('sort') || defaultSort
|
let filterSort: string = $page.query.get('sort') || defaultSort
|
||||||
let countryFlagId: string
|
let countryFlagId: string
|
||||||
|
$: filtered = filterCountry !== defaultCountry || filterSort !== defaultSort
|
||||||
|
$: latestPhoto = photos[0]
|
||||||
|
|
||||||
|
|
||||||
// Pages related informations
|
// Pages related informations
|
||||||
let currentPage: number = 1
|
let currentPage: number = 1
|
||||||
@@ -56,10 +59,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update URL filtering params from filter values
|
// Update URL filtering params from filter values
|
||||||
if (filtered && filterCountry && filterSort) {
|
if (browser) {
|
||||||
urlFiltersParams.set('country', filterCountry)
|
urlFiltersParams.set('country', filterCountry)
|
||||||
urlFiltersParams.set('sort', filterSort)
|
urlFiltersParams.set('sort', filterSort)
|
||||||
goto(`${$page.path}?${urlFiltersParams.toString()}`, { keepfocus:true, replaceState:true, noscroll:true })
|
goto(`${$page.path}?${urlFiltersParams.toString()}`, { replaceState: true, keepfocus: true, noscroll: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,53 +72,24 @@
|
|||||||
*/
|
*/
|
||||||
// Country select
|
// Country select
|
||||||
const handleCountryChange = ({ detail: value }) => {
|
const handleCountryChange = ({ detail: value }) => {
|
||||||
console.log('country change:', value)
|
filterCountry = value === defaultCountry ? defaultCountry : value
|
||||||
filtered = true
|
|
||||||
filterCountry = value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort select
|
// Sort select
|
||||||
const handleSortChange = ({ detail: value }) => {
|
const handleSortChange = ({ detail: value }) => {
|
||||||
console.log('sort change:', value)
|
filterSort = value === defaultSort ? defaultSort : value
|
||||||
filtered = true
|
|
||||||
filterSort = value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset filters
|
||||||
/**
|
|
||||||
* Reset filters
|
|
||||||
*/
|
|
||||||
const resetFiltered = () => {
|
const resetFiltered = () => {
|
||||||
filtered = false
|
|
||||||
filterCountry = defaultCountry
|
filterCountry = defaultCountry
|
||||||
filterSort = defaultSort
|
filterSort = defaultSort
|
||||||
goto($page.path, { replaceState: true, noscroll: true })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load photos
|
* Load photos
|
||||||
*/
|
*/
|
||||||
// Load more photos from CTA
|
|
||||||
const loadMorePhotos = async () => {
|
|
||||||
// Append more photos from API including options and page
|
|
||||||
const newPhotos: any = await loadPhotos(currentPage + 1)
|
|
||||||
console.log(newPhotos)
|
|
||||||
|
|
||||||
if (newPhotos) {
|
|
||||||
photos = [...photos, ...newPhotos]
|
|
||||||
|
|
||||||
// Define actions if the number of new photos is the expected ones
|
|
||||||
if (newPhotos.length === Number(import.meta.env.VITE_GRID_INCREMENT)) {
|
|
||||||
// Increment the current page
|
|
||||||
currentPage++
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increment the currently visible amount of photos
|
|
||||||
currentPhotosAmount += newPhotos.length
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// [function] Load photos helper
|
// [function] Load photos helper
|
||||||
const loadPhotos = async (page?: number) => {
|
const loadPhotos = async (page?: number) => {
|
||||||
const res = fetchAPI(`
|
const res = fetchAPI(`
|
||||||
@@ -151,6 +125,25 @@
|
|||||||
throw new Error('Error while loading new photos')
|
throw new Error('Error while loading new photos')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load more photos from CTA
|
||||||
|
const loadMorePhotos = async () => {
|
||||||
|
// Append more photos from API including options and page
|
||||||
|
const newPhotos: any = await loadPhotos(currentPage + 1)
|
||||||
|
|
||||||
|
if (newPhotos) {
|
||||||
|
photos = [...photos, ...newPhotos]
|
||||||
|
|
||||||
|
// Define actions if the number of new photos is the expected ones
|
||||||
|
if (newPhotos.length === Number(import.meta.env.VITE_GRID_INCREMENT)) {
|
||||||
|
// Increment the current page
|
||||||
|
currentPage++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment the currently visible amount of photos
|
||||||
|
currentPhotosAmount += newPhotos.length
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Metas
|
<Metas
|
||||||
@@ -175,14 +168,15 @@
|
|||||||
name="country" id="filter_country"
|
name="country" id="filter_country"
|
||||||
options={[
|
options={[
|
||||||
{
|
{
|
||||||
value: 'all',
|
value: defaultCountry,
|
||||||
name: 'Worldwide',
|
name: 'Worldwide',
|
||||||
default: filterCountry === defaultCountry
|
default: true,
|
||||||
|
selected: filterCountry === defaultCountry,
|
||||||
},
|
},
|
||||||
...countries.map(({ slug, name }) => ({
|
...countries.map(({ slug, name }) => ({
|
||||||
value: slug,
|
value: slug,
|
||||||
name,
|
name,
|
||||||
default: filterCountry === slug,
|
selected: filterCountry === slug,
|
||||||
}))
|
}))
|
||||||
]}
|
]}
|
||||||
on:change={handleCountryChange}
|
on:change={handleCountryChange}
|
||||||
@@ -199,8 +193,17 @@
|
|||||||
<Select
|
<Select
|
||||||
name="sort" id="filter_sort"
|
name="sort" id="filter_sort"
|
||||||
options={[
|
options={[
|
||||||
{ value: 'latest', name: 'Latest photos', default: filterSort === defaultSort },
|
{
|
||||||
{ value: 'oldest', name: 'Oldest photos', default: filterSort === 'oldest' },
|
value: 'latest',
|
||||||
|
name: 'Latest photos',
|
||||||
|
default: true,
|
||||||
|
selected: filterSort === defaultSort
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'oldest',
|
||||||
|
name: 'Oldest photos',
|
||||||
|
selected: filterSort === 'oldest'
|
||||||
|
},
|
||||||
]}
|
]}
|
||||||
on:change={handleSortChange}
|
on:change={handleSortChange}
|
||||||
value={filterSort}
|
value={filterSort}
|
||||||
@@ -233,7 +236,7 @@
|
|||||||
|
|
||||||
<section class="photos__content">
|
<section class="photos__content">
|
||||||
<div class="grid container">
|
<div class="grid container">
|
||||||
{#if photos}
|
{#if photos.length}
|
||||||
<div class="photos__grid">
|
<div class="photos__grid">
|
||||||
{#each photos as { image, slug, location }}
|
{#each photos as { image, slug, location }}
|
||||||
<div class="photo shadow-photo">
|
<div class="photo shadow-photo">
|
||||||
@@ -246,8 +249,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="controls grid">
|
<div class="controls grid">
|
||||||
<p class="controls__date" title={dayjs(lastUpdated).format('DD/MM/YYYY, hh:mm')}>
|
<p class="controls__date" title={dayjs(latestPhoto.date_created).format('DD/MM/YYYY, hh:mm')}>
|
||||||
Last updated: <time datetime={dayjs(lastUpdated).format('YYYY-MM-DD')}>{dayjs().to(dayjs(lastUpdated))}</time>
|
Last updated: <time datetime={dayjs(latestPhoto.date_created).format('YYYY-MM-DD')}>{dayjs().to(dayjs(latestPhoto.date_created))}</time>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
@@ -316,10 +319,7 @@
|
|||||||
slug
|
slug
|
||||||
country { slug }
|
country { slug }
|
||||||
}
|
}
|
||||||
}
|
date_created
|
||||||
|
|
||||||
total_published: photo_aggregated {
|
|
||||||
count { id }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
country: country (
|
country: country (
|
||||||
@@ -331,20 +331,25 @@
|
|||||||
slug
|
slug
|
||||||
}
|
}
|
||||||
|
|
||||||
lastUpdated: photo (limit: 1, sort: "-date_created", filter: { status: { _eq: "published" }}) {
|
# Total
|
||||||
date_created
|
total_published: photo_aggregated {
|
||||||
|
count { id }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`)
|
`)
|
||||||
|
|
||||||
const { data } = res
|
const { data } = res
|
||||||
|
|
||||||
|
// Calculate total of photos (if default or specific)
|
||||||
|
const totalPhotos = queryCountry === 'all'
|
||||||
|
? data.total_published[0].count.id
|
||||||
|
: stuff.countries.find((country: any) => country.slug === queryCountry).count
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
photos: data.photos,
|
photos: data.photos,
|
||||||
filteredCountryExists: data.country.length > 0,
|
filteredCountryExists: data.country.length > 0,
|
||||||
totalPhotos: data.total_published[0].count.id,
|
totalPhotos,
|
||||||
lastUpdated: data.lastUpdated[0].date_created,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user