Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
oien
Clouds - Firebase - Movies
Commits
23d85d01
Commit
23d85d01
authored
Jan 10, 2022
by
erlendoeien
Browse files
Add infinite scroll and refactor
parent
317ea561
Changes
8
Hide whitespace changes
Inline
Side-by-side
src/components/IconButton.vue
View file @
23d85d01
<
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
>
...
...
src/components/Table.vue
0 → 100644
View file @
23d85d01
<
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
>
src/components/TableHead.vue
0 → 100644
View file @
23d85d01
<
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
>
src/components/TableRow.vue
0 → 100644
View file @
23d85d01
<
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
>
src/hooks/useMatchedMovies.ts
View file @
23d85d01
...
...
@@ -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
};
}
src/types.ts
View file @
23d85d01
...
...
@@ -7,7 +7,6 @@ export interface IMovieRaw {
title
:
string
|
number
;
}
export
interface
IMovie
extends
IMovieRaw
{
// extends Pick<IMovieRaw, "id" | "genre"> {
year
:
string
;
title
:
string
;
}
...
...
src/views/Movies.vue
View file @
23d85d01
...
...
@@ -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
>
...
...
src/views/Wishlist.vue
View file @
23d85d01
...
...
@@ -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
();
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment