Skip to content

Commit

Permalink
client: implement search functionality compatible with pagination
Browse files Browse the repository at this point in the history
server: search gives just one page size and is case insensitive
  • Loading branch information
EliasSchaut committed Sep 29, 2024
1 parent 2abe1c0 commit d9d9351
Show file tree
Hide file tree
Showing 11 changed files with 133 additions and 29 deletions.
2 changes: 1 addition & 1 deletion client/components/form/input/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export default defineComponent({
},
label: {
type: String,
required: true,
default: null,
},
placeholder: {
type: String,
Expand Down
6 changes: 3 additions & 3 deletions client/components/layout/nav.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<div class="flex">
<!-- NavBar left side -->
<nuxt-link
class="flex flex-shrink-0 items-center text-xl font-semibold leading-6 text-secondary-900 hover:underline dark:text-white"
class="flex flex-shrink-0 items-center text-xl font-bold leading-6 text-secondary-900 hover:underline dark:text-white"
href="/"
>
{{ proj_name }}
Expand All @@ -25,7 +25,7 @@
$route.path.split('/')[1] === link.href.split('/')[1]
? 'border-primary-500 text-secondary-900 dark:text-white'
: 'border-transparent text-secondary-500 hover:border-secondary-300 hover:text-secondary-700 dark:hover:text-white',
'inline-flex items-center border-b-2 px-1 pt-1 text-sm font-medium',
'inline-flex items-center border-b-2 px-1 pt-1 text-sm font-semibold',
]"
>{{ link.name }}
</NuxtLink>
Expand Down Expand Up @@ -121,7 +121,7 @@ export default defineComponent({
href: '/reports',
},
{
name: t('nav.pages.reports'),
name: t('nav.pages.requests'),
href: '/requests',
},
{
Expand Down
52 changes: 52 additions & 0 deletions client/components/search/artist_title.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<template>
<div class="flex flex-col gap-x-4 gap-y-2 sm:flex-row">
<FormInput
id="track_title"
class="w-full"
type="text"
@input="input_track"
:icon="MusicalNoteIcon"
placeholder="Search by track title..."
/>
<FormInput
id="artist_name"
class="w-full"
type="text"
@input="input_artist"
:icon="UserIcon"
placeholder="Search by artist name..."
/>
</div>
</template>

<script lang="ts">
import { MusicalNoteIcon, UserIcon } from '@heroicons/vue/24/outline';
export default defineComponent({
setup() {
return {
artist_name: ref<string>(''),
track_title: ref<string>(''),
};
},
emits: ['search_query'],
methods: {
MusicalNoteIcon,
UserIcon,
emit_search_query() {
this.$emit('search_query', {
artist_name: this.artist_name.length >= 3 ? this.artist_name : '',
track_title: this.track_title.length >= 3 ? this.track_title : '',
});
},
input_track(event: InputEvent) {
this.track_title = event.target?.value;
this.emit_search_query();
},
input_artist(event: InputEvent) {
this.artist_name = event.target?.value;
this.emit_search_query();
},
},
});
</script>
File renamed without changes.
7 changes: 7 additions & 0 deletions client/components/table/empty.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<template>
<p
class="w-full rounded-md bg-secondary-100 p-10 text-center text-xl italic dark:bg-secondary-900"
>
<slot />
</p>
</template>
3 changes: 2 additions & 1 deletion client/locales/de-DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,12 @@
"listen_on": "Anhören:"
},
"table": {
"empty": "Keine Tracks gefunden!",
"head": {
"artist": "Künstler",
"info": "Info",
"report": "Melden",
"title": "Titel"
"title": "Track"
},
"reported": "Gemeldet"
}
Expand Down
3 changes: 2 additions & 1 deletion client/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,12 @@
"listen_on": "Listen on:"
},
"table": {
"empty": "No tracks found!",
"head": {
"artist": "Artist",
"info": "Info",
"report": "Report",
"title": "Title"
"title": "Track"
},
"reported": "Reported"
}
Expand Down
61 changes: 53 additions & 8 deletions client/pages/[[query]].vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
<template>
<div class="px-8">
<div class="-mx-4 pt-8 sm:px-6 lg:px-8">
<Search
@input="search = $event.target.value"
:value="route.params.query ?? ''"
/>
<TableStriped v-if="tracks.length">
<SearchArtistTitle @search_query="search_query" class="mb-4 w-full" />
<TableStriped v-if="!table_empty">
<thead>
<tr>
<TableHead first>{{ $t('tracks.table.head.info') }}</TableHead>
Expand All @@ -21,7 +18,10 @@
</tr>
</thead>
<tbody class="bg-white">
<template v-for="track in tracks" :key="track.title">
<template
v-for="track in is_searching ? tracks_searched : tracks"
:key="track.title"
>
<TableRow
v-if="
search === '' ||
Expand Down Expand Up @@ -74,11 +74,14 @@
</tbody>
</TableStriped>
<Pagination
v-if="tracks.length"
v-if="tracks.length && !is_searching"
@update:current_page="change_page"
:total_pages="total_pages"
:current_page="current_page"
/>
<TableEmpty v-if="table_empty">
{{ $t('tracks.table.empty') }}
</TableEmpty>
</div>
</div>

Expand Down Expand Up @@ -118,13 +121,29 @@ const count_query = gql`
}
`;
const search_query = gql`
query search_tracks($search_query: SearchInputModel!) {
tracks_search(search_query: $search_query) {
id
title
artist {
name
}
reported
}
}
`;
export default defineComponent({
setup() {
const route = useRoute();
const page_size = useRuntimeConfig().public.page_size;
const search = ref<string>(route.params.query ?? '');
const tracks_total = ref<TrackType>([]);
let tracks = ref<TrackType>([]);
let tracks_searched = ref<TrackType>([]);
const tracks_total = ref<TrackType>([]);
const is_searching = ref<boolean>(false);
let search_input_timeout: number | null = null;
const total_pages = ref<number>(1);
const fetched_pages = ref<number>(1);
const current_page = ref<number>(1);
Expand All @@ -145,12 +164,20 @@ export default defineComponent({
search,
tracks,
tracks_total,
tracks_searched,
total_pages,
current_page,
fetched_pages,
page_size,
is_searching,
search_input_timeout,
};
},
computed: {
table_empty() {
return this.is_searching && this.tracks_searched.length === 0;
},
},
methods: {
async get_new_tracks() {
const { data } = await useAsyncQuery<[TrackType]>(track_query, {
Expand All @@ -173,6 +200,24 @@ export default defineComponent({
);
this.current_page = page;
},
async search_query(query: { artist_name?: string; track_title?: string }) {
clearTimeout(this.search_input_timeout);
if (query.artist_name || query.track_title) {
this.search_input_timeout = setTimeout(async () => {
const { data } = await useAsyncQuery<[TrackType]>(search_query, {
search_query: {
artist_name: query.artist_name,
track_title: query.track_title,
},
});
this.tracks_searched = data?.value?.tracks_search ?? [];
this.is_searching = true;
}, 500);
} else {
this.is_searching = false;
this.tracks_searched = [];
}
},
report_track(track_id: number) {
this.tracks[this.tracks.findIndex((t) => t.id === track_id)].reported =
true;
Expand Down
7 changes: 2 additions & 5 deletions client/pages/reports/[[query]].vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,9 @@
</template>
</tbody>
</TableStriped>
<p
v-else
class="w-full rounded-md bg-secondary-100 p-10 text-center text-xl italic"
>
<TableEmpty v-else>
{{ $t('report.table.empty') }}
</p>
</TableEmpty>
</div>
</div>
</template>
Expand Down
7 changes: 1 addition & 6 deletions client/pages/requests/[[query]].vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,7 @@
</template>
</tbody>
</TableStriped>
<p
v-else
class="mt-4 w-full rounded-md bg-secondary-100 p-10 text-center text-xl italic"
>
${{ $t('request.table.empty') }}
</p>
<TableEmpty v-else> ${{ $t('request.table.empty') }} </TableEmpty>
</div>
</div>

Expand Down
14 changes: 10 additions & 4 deletions server/graphql/track/track.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { MusicApiService } from '@/common/services/music_api/music_api.service';
import { SearchInputModel } from '@/types/models/inputs/search.input';
import { CursorInputModel } from '@/types/models/inputs/cursor.input';
import { CountModel } from '@/types/models/count.model';
import { Artist } from '@prisma/client';
import { Artist, Prisma } from '@prisma/client';

@Injectable()
export class TrackService {
Expand All @@ -24,15 +24,20 @@ export class TrackService {
search_query: SearchInputModel,
ctx: CtxType,
): Promise<TrackModel[]> {
const queries = [];
const queries: Prisma.TrackWhereInput[] = [];
if (search_query.track_title.length > 0) {
queries.push({ title: { contains: search_query.track_title } });
queries.push({
title: { contains: search_query.track_title, mode: 'insensitive' },
});
}
if (search_query.artist_name.length > 0) {
queries.push({
artist: { name: { contains: search_query.artist_name } },
artist: {
name: { contains: search_query.artist_name, mode: 'insensitive' },
},
});
}
if (queries.length === 0) return [];

return this.prisma.track.findMany({
select: {
Expand All @@ -49,6 +54,7 @@ export class TrackService {
AND: queries,
},
orderBy: { title: 'asc' },
take: Number(process.env.TABLE_PAGE_SIZE),
});
}

Expand Down

0 comments on commit d9d9351

Please sign in to comment.