Skip to content

Commit f459ddd

Browse files
committed
refactor: search people
1 parent adb607c commit f459ddd

File tree

10 files changed

+149
-166
lines changed

10 files changed

+149
-166
lines changed

Diff for: web/src/lib/components/album-page/albums-controls.svelte

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@
100100

101101
<!-- Search Albums -->
102102
<div class="hidden xl:block h-10 xl:w-60 2xl:w-80">
103-
<SearchBar placeholder="Search albums" bind:name={searchQuery} isSearching={false} />
103+
<SearchBar placeholder="Search albums" bind:name={searchQuery} showLoadingSpinner={false} />
104104
</div>
105105

106106
<!-- Create Album -->

Diff for: web/src/lib/components/elements/search-bar.svelte

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
88
export let name: string;
99
export let roundedBottom = true;
10-
export let isSearching: boolean;
10+
export let showLoadingSpinner: boolean;
1111
export let placeholder: string;
1212
1313
const dispatch = createEventDispatcher<{ search: SearchOptions; reset: void }>();
@@ -35,7 +35,7 @@
3535
bind:value={name}
3636
on:input={() => dispatch('search', { force: false })}
3737
/>
38-
{#if isSearching}
38+
{#if showLoadingSpinner}
3939
<div class="flex place-items-center">
4040
<LoadingSpinner />
4141
</div>

Diff for: web/src/lib/components/faces-page/assign-face-side-panel.svelte

+9-46
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,17 @@
11
<script lang="ts">
2-
import { maximumLengthSearchPeople, timeBeforeShowLoadingSpinner } from '$lib/constants';
2+
import { timeBeforeShowLoadingSpinner } from '$lib/constants';
33
import { photoViewer } from '$lib/stores/assets.store';
44
import { getAssetThumbnailUrl, getPeopleThumbnailUrl } from '$lib/utils';
5-
import { handleError } from '$lib/utils/handle-error';
6-
import { getPersonNameWithHiddenValue, searchNameLocal } from '$lib/utils/person';
7-
import {
8-
AssetTypeEnum,
9-
ThumbnailFormat,
10-
searchPerson,
11-
type AssetFaceResponseDto,
12-
type PersonResponseDto,
13-
} from '@immich/sdk';
5+
import { getPersonNameWithHiddenValue } from '$lib/utils/person';
6+
import { AssetTypeEnum, ThumbnailFormat, type AssetFaceResponseDto, type PersonResponseDto } from '@immich/sdk';
147
import { mdiArrowLeftThin, mdiClose, mdiMagnify, mdiPlus } from '@mdi/js';
158
import { createEventDispatcher } from 'svelte';
169
import { linear } from 'svelte/easing';
1710
import { fly } from 'svelte/transition';
1811
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
1912
import Icon from '../elements/icon.svelte';
2013
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
14+
import SearchPeople from '$lib/components/faces-page/search-people.svelte';
2115
2216
export let peopleWithFaces: AssetFaceResponseDto[];
2317
export let allPeople: PersonResponseDto[];
@@ -31,8 +25,6 @@
3125
3226
// search people
3327
let searchedPeople: PersonResponseDto[] = [];
34-
let searchedPeopleCopy: PersonResponseDto[] = [];
35-
let searchWord: string;
3628
let searchFaces = false;
3729
let searchName = '';
3830
@@ -116,33 +108,6 @@
116108
isShowLoadingNewPerson = false;
117109
dispatch('createPerson', newFeaturePhoto);
118110
};
119-
120-
const searchPeople = async () => {
121-
if ((searchedPeople.length < maximumLengthSearchPeople && searchName.startsWith(searchWord)) || searchName === '') {
122-
return;
123-
}
124-
const timeout = setTimeout(() => (isShowLoadingSearch = true), timeBeforeShowLoadingSpinner);
125-
try {
126-
const data = await searchPerson({ name: searchName });
127-
searchedPeople = data;
128-
searchedPeopleCopy = data;
129-
searchWord = searchName;
130-
} catch (error) {
131-
handleError(error, "Can't search people");
132-
} finally {
133-
clearTimeout(timeout);
134-
}
135-
136-
isShowLoadingSearch = false;
137-
};
138-
139-
$: {
140-
searchedPeople = searchNameLocal(searchName, searchedPeopleCopy, 20);
141-
}
142-
143-
const initInput = (element: HTMLInputElement) => {
144-
element.focus();
145-
};
146111
</script>
147112

148113
<section
@@ -200,13 +165,11 @@
200165
</div>
201166
</button>
202167
<div class="w-full flex">
203-
<input
204-
class="w-full gap-2 bg-immich-bg dark:bg-immich-dark-bg"
205-
type="text"
206-
placeholder="Name or nickname"
207-
bind:value={searchName}
208-
on:input={searchPeople}
209-
use:initInput
168+
<SearchPeople
169+
type="input"
170+
bind:searchName
171+
bind:isSearching={isShowLoadingSearch}
172+
bind:searchedPeopleLocal={searchedPeople}
210173
/>
211174
{#if isShowLoadingSearch}
212175
<div>

Diff for: web/src/lib/components/faces-page/people-list.svelte

+13-38
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,41 @@
11
<script lang="ts">
2-
import { maximumLengthSearchPeople, timeBeforeShowLoadingSpinner } from '$lib/constants';
3-
import { handleError } from '$lib/utils/handle-error';
4-
import { searchNameLocal } from '$lib/utils/person';
5-
import { searchPerson, type PersonResponseDto } from '@immich/sdk';
2+
import { type PersonResponseDto } from '@immich/sdk';
63
import { createEventDispatcher } from 'svelte';
74
import FaceThumbnail from './face-thumbnail.svelte';
8-
import SearchBar from '../elements/search-bar.svelte';
5+
import SearchPeople from '$lib/components/faces-page/search-people.svelte';
96
107
export let screenHeight: number;
118
export let people: PersonResponseDto[];
129
export let peopleCopy: PersonResponseDto[];
1310
export let unselectedPeople: PersonResponseDto[];
1411
1512
let name = '';
16-
let searchWord: string;
13+
let showPeople: PersonResponseDto[];
1714
let isSearchingPeople = false;
1815
1916
let dispatch = createEventDispatcher<{
2017
select: PersonResponseDto;
2118
}>();
2219
2320
$: {
24-
people = peopleCopy.filter(
21+
showPeople = people.filter(
2522
(person) => !unselectedPeople.some((unselectedPerson) => unselectedPerson.id === person.id),
2623
);
27-
if (name) {
28-
people = searchNameLocal(name, people, maximumLengthSearchPeople);
29-
}
3024
}
3125
32-
const searchPeople = async (force: boolean) => {
33-
if (name === '') {
34-
people = peopleCopy;
35-
return;
36-
}
37-
if (!force && people.length < maximumLengthSearchPeople && name.startsWith(searchWord)) {
38-
return;
39-
}
40-
41-
const timeout = setTimeout(() => (isSearchingPeople = true), timeBeforeShowLoadingSpinner);
42-
try {
43-
people = await searchPerson({ name });
44-
searchWord = name;
45-
} catch (error) {
46-
handleError(error, "Can't search people");
47-
} finally {
48-
clearTimeout(timeout);
49-
}
50-
51-
isSearchingPeople = false;
26+
const handleResetSearch = () => {
27+
people = peopleCopy;
5228
};
5329
</script>
5430

5531
<div class=" w-40 sm:w-48 md:w-96 h-14 mb-8">
56-
<SearchBar
57-
bind:name
58-
isSearching={isSearchingPeople}
32+
<SearchPeople
33+
type="searchBar"
5934
placeholder="Search people"
60-
on:reset={() => {
61-
people = peopleCopy;
62-
}}
63-
on:search={({ detail }) => searchPeople(detail.force ?? false)}
35+
onReset={handleResetSearch}
36+
bind:searchName={name}
37+
bind:searchedPeopleLocal={people}
38+
bind:isSearching={isSearchingPeople}
6439
/>
6540
</div>
6641

@@ -69,7 +44,7 @@
6944
style:max-height={screenHeight - 400 + 'px'}
7045
>
7146
<div class="grid-col-2 grid gap-8 md:grid-cols-3 lg:grid-cols-6 xl:grid-cols-8 2xl:grid-cols-10">
72-
{#each people as person (person.id)}
47+
{#each showPeople as person (person.id)}
7348
<FaceThumbnail
7449
{person}
7550
on:click={() => {
+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<script lang="ts">
2+
import SearchBar from '$lib/components/elements/search-bar.svelte';
3+
import { maximumLengthSearchPeople, timeBeforeShowLoadingSpinner } from '$lib/constants';
4+
import { handleError } from '$lib/utils/handle-error';
5+
import { searchNameLocal } from '$lib/utils/person';
6+
import { searchPerson, type PersonResponseDto } from '@immich/sdk';
7+
8+
export let searchName: string;
9+
export let searchedPeopleLocal: PersonResponseDto[];
10+
export let type: 'searchBar' | 'input';
11+
export let showLoadingSpinner: boolean = false;
12+
export let isSearching: boolean = false;
13+
export let placeholder: string = 'Name or nickname';
14+
export let onReset = () => {};
15+
export let onSearch = () => {};
16+
17+
let searchArray: PersonResponseDto[] = [];
18+
let searchWord: string;
19+
let abortController: AbortController | null = null;
20+
21+
const search = () => {
22+
searchedPeopleLocal = searchNameLocal(searchName, searchArray, maximumLengthSearchPeople);
23+
};
24+
25+
export let handleSearch = async (force?: boolean, name?: string) => {
26+
isSearching = true;
27+
searchName = name ?? searchName;
28+
onSearch();
29+
if (searchName === '') {
30+
onReset();
31+
isSearching = false;
32+
return;
33+
}
34+
if (!force && searchArray.length < maximumLengthSearchPeople && searchName.startsWith(searchWord)) {
35+
search();
36+
isSearching = false;
37+
return;
38+
}
39+
if (abortController) {
40+
abortController.abort();
41+
}
42+
abortController = new AbortController();
43+
const timeout = setTimeout(() => (showLoadingSpinner = true), timeBeforeShowLoadingSpinner);
44+
try {
45+
const data = await searchPerson({ name: searchName }, { signal: abortController?.signal });
46+
abortController = null;
47+
searchArray = data;
48+
searchWord = searchName;
49+
} catch (error) {
50+
handleError(error, "Can't search people");
51+
} finally {
52+
clearTimeout(timeout);
53+
}
54+
search();
55+
isSearching = false;
56+
showLoadingSpinner = false;
57+
};
58+
59+
const initInput = (element: HTMLInputElement) => {
60+
element.focus();
61+
};
62+
</script>
63+
64+
{#if type === 'searchBar'}
65+
<SearchBar
66+
bind:name={searchName}
67+
{showLoadingSpinner}
68+
{placeholder}
69+
on:reset={onReset}
70+
on:search={({ detail }) => handleSearch(detail.force ?? false)}
71+
/>
72+
{:else}
73+
<input
74+
class="w-full gap-2 bg-immich-bg dark:bg-immich-dark-bg"
75+
type="text"
76+
{placeholder}
77+
bind:value={searchName}
78+
on:input={() => handleSearch(false)}
79+
use:initInput
80+
/>
81+
{/if}

Diff for: web/src/lib/components/shared-components/change-location.svelte

+4-4
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
let suggestedPlaces: PlacesResponseDto[] = [];
2424
let searchWord: string;
2525
let isSearching = false;
26-
let showSpinner = false;
26+
let showLoadingSpinner = false;
2727
let suggestionContainer: HTMLDivElement;
2828
let hideSuggestion = false;
2929
let addClipMapMarker: (long: number, lat: number) => void;
@@ -73,7 +73,7 @@
7373
7474
// TODO: refactor setTimeout/clearTimeout logic - there are no less than 12 places that duplicate this code
7575
isSearching = true;
76-
const timeout = setTimeout(() => (showSpinner = true), timeBeforeShowLoadingSpinner);
76+
const timeout = setTimeout(() => (showLoadingSpinner = true), timeBeforeShowLoadingSpinner);
7777
try {
7878
places = await searchPlaces({ name: searchWord });
7979
} catch (error) {
@@ -82,7 +82,7 @@
8282
} finally {
8383
clearTimeout(timeout);
8484
isSearching = false;
85-
showSpinner = false;
85+
showLoadingSpinner = false;
8686
}
8787
};
8888
@@ -111,7 +111,7 @@
111111
<SearchBar
112112
placeholder="Search places"
113113
bind:name={searchWord}
114-
isSearching={showSpinner}
114+
{showLoadingSpinner}
115115
on:reset={() => {
116116
suggestedPlaces = [];
117117
}}

Diff for: web/src/lib/components/shared-components/search-bar/search-people-section.svelte

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
<div id="people-selection" class="-mb-4">
5757
<div class="flex items-center w-full justify-between gap-6">
5858
<p class="immich-form-label py-3">PEOPLE</p>
59-
<SearchBar bind:name placeholder="Filter people" isSearching={false} />
59+
<SearchBar bind:name placeholder="Filter people" showLoadingSpinner={false} />
6060
</div>
6161

6262
<div class="flex -mx-1 max-h-64 gap-1 mt-2 flex-wrap overflow-y-auto immich-scrollbar">

Diff for: web/src/routes/(user)/albums/+page.svelte

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
/>
3030
</div>
3131
<div class="w-60">
32-
<SearchBar placeholder="Search albums" bind:name={searchQuery} isSearching={false} />
32+
<SearchBar placeholder="Search albums" bind:name={searchQuery} showLoadingSpinner={false} />
3333
</div>
3434
</div>
3535

0 commit comments

Comments
 (0)