Commit 23d85d01 authored by erlendoeien's avatar erlendoeien
Browse files

Add infinite scroll and refactor

parent 317ea561
<template>
<Button @click="onClick"
><font-awesome-icon class="hover:scale-125 icon" size="lg" :icon="icon" /><slot
/></Button>
<button><font-awesome-icon class="hover:scale-125 icon" size="lg" :icon="icon" /><slot /></button>
</template>
<script setup lang="ts">
......@@ -9,12 +7,10 @@ import { toRefs } from "@vue/reactivity";
interface IIconButtonProps {
icon: string;
onClick(): void;
//TODO: Pass along Font-awesome-icon props
}
const props = defineProps<IIconButtonProps>();
const { icon, onClick } = toRefs(props);
const { icon } = toRefs(props);
</script>
<style>
......
<template>
<table>
<TableHead :isWishlist="isWishlist" />
<tbody v-for="row in data">
<TableRow
:rowData="row"
:key="row.id"
:adminIcon="isWishlist ? 'heart-broken' : 'heart'"
:adminFunc="adminFunc"
/>
</tbody>
</table>
</template>
<script setup lang="ts">
import { toRefs } from "vue";
import { IMovie } from "../types";
import TableHead from "./TableHead.vue";
import TableRow from "./TableRow.vue";
interface ITableProps {
isWishlist: boolean;
data: IMovie[];
adminFunc(id: number): void;
}
const props = defineProps<ITableProps>();
const { data, adminFunc, isWishlist } = toRefs(props);
</script>
<template>
<thead>
<th>Title</th>
<th>Year</th>
<th>Genre</th>
<th>{{ isWishlist ? "Remove from" : "Add to" }} wishlist</th>
</thead>
</template>
<script setup lang="ts">
import { toRefs } from "vue";
interface ITableHeadProps {
isWishlist: boolean;
}
const props = defineProps<ITableHeadProps>();
const { isWishlist } = toRefs(props);
</script>
<template>
<tr>
<td>{{ rowData.title }}</td>
<td>{{ rowData.year }}</td>
<td>{{ rowData.genre }}</td>
<td><IconButton :icon="adminIcon" @click="adminFunc(rowData.id)" /></td>
</tr>
</template>
<script setup lang="ts">
import { toRefs } from "vue";
import { IMovie } from "../types";
import IconButton from "./IconButton.vue";
interface ITableRowProps {
rowData: IMovie;
adminFunc(id: number): void;
adminIcon: string;
}
const props = defineProps<ITableRowProps>();
const { rowData, adminFunc, adminIcon } = toRefs(props);
</script>
......@@ -4,16 +4,23 @@ import _debounce from "lodash/debounce";
export default function useMatchedMovies(movies: Ref<IMovie[]>) {
const searchQuery = ref("");
const limit = ref(50);
const matchPredicate = ({ genre, title, year }: IMovie) =>
genre.indexOf(searchQuery.value) > -1 ||
title.indexOf(searchQuery.value) > -1 ||
year.indexOf(searchQuery.value) > -1;
const loadMore = () => {
limit.value += 50;
};
const hasMore = computed(() => movies.value && limit.value < movies.value.length);
const moviesMatchingSearchQuery = computed(() => {
if (searchQuery.value.length === 0) return movies.value;
return movies.value.filter(matchPredicate);
if (searchQuery.value.length === 0) return movies.value.slice(0, limit.value);
return movies.value.filter(matchPredicate).slice(0, limit.value);
});
return { searchQuery, moviesMatchingSearchQuery };
return { searchQuery, hasMore, loadMore, moviesMatchingSearchQuery };
}
......@@ -7,7 +7,6 @@ export interface IMovieRaw {
title: string | number;
}
export interface IMovie extends IMovieRaw {
// extends Pick<IMovieRaw, "id" | "genre"> {
year: string;
title: string;
}
......
......@@ -6,32 +6,24 @@
<h3>Loading...</h3>
<font-awesome-icon icon="spinner" spin />
</div>
<table v-else>
<thead>
<th>Title</th>
<th>Year</th>
<th>Genre</th>
<th>Add to wishlist</th>
</thead>
<tr v-for="movie in filteredMovies" :key="movie.id">
<td>{{ movie.title }}</td>
<td>{{ movie.year }}</td>
<td>{{ movie.genre }}</td>
<td><IconButton icon="heart" :onClick="() => addWish(movie.id)"/></td>
</tr>
</table>
<Table :data="filteredMovies" :adminFunc="addWish" :isWishlist="false" v-else />
<Button class="mx-auto mb-8" @click="loadMore">Load more</Button>
</div>
</template>
<script setup lang="ts">
import { useWishlistMovies, useMovies, useWishlist, useMatchedMovies } from "../hooks";
import IconButton from "../components/IconButton.vue";
import Table from "../components/Table.vue";
import Button from "../components/Button.vue";
const { movies } = useMovies();
const { wishlist, addWish } = useWishlist();
const { wishlistFilteredMovies } = useWishlistMovies(movies, wishlist, false);
const { searchQuery, moviesMatchingSearchQuery: filteredMovies } =
useMatchedMovies(wishlistFilteredMovies);
const {
searchQuery,
loadMore,
moviesMatchingSearchQuery: filteredMovies,
} = useMatchedMovies(wishlistFilteredMovies);
</script>
<style>
......
......@@ -2,27 +2,17 @@
<h1>Wishlist</h1>
<div v-if="isEmpty">
<h3>No movies in wishlist</h3>
<button @click="redirect">Add new movies</button>
<Button @click="redirect">Add new movies</Button>
</div>
<div v-else>
<Table :data="filteredMovies" :adminFunc="deleteWish" isWishlist />
</div>
<table v-else>
<thead>
<th>Title</th>
<th>Year</th>
<th>Genre</th>
<th>Remove from wishlist</th>
</thead>
<tr v-for="movie in filteredMovies" :key="movie.id">
<td>{{ movie.title }}</td>
<td>{{ movie.year }}</td>
<td>{{ movie.genre }}</td>
<td><IconButton :onClick="() => deleteWish(movie.id)" icon="heart-broken" /></td>
</tr>
</table>
</template>
<script setup lang="ts">
import { useRouter } from "vue-router";
import { useWishlistMovies, useMovies, useWishlist } from "../hooks";
import IconButton from "../components/IconButton.vue";
import Button from "../components/Button.vue";
import Table from "../components/Table.vue";
const { movies } = useMovies();
const { wishlist, deleteWish, isEmpty } = useWishlist();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment