+4
-4
src/hooks/useFollows.ts
+4
-4
src/hooks/useFollows.ts
···
1
-
import { useState } from "react";
2
import { apiClient } from "../lib/api/client";
3
import { FOLLOW_CONFIG } from "../config/constants";
4
import { getAtprotoApp } from "../lib/utils/platform";
···
15
const [isFollowing, setIsFollowing] = useState(false);
16
const [isCheckingFollowStatus, setIsCheckingFollowStatus] = useState(false);
17
18
-
async function followSelectedUsers(
19
onUpdate: (message: string) => void,
20
-
): Promise<void> {
21
if (!session || isFollowing) return;
22
23
const destinationApp = getAtprotoApp(destinationAppId);
···
156
} finally {
157
setIsFollowing(false);
158
}
159
-
}
160
161
return {
162
isFollowing,
···
1
+
import { useState, useCallback } from "react";
2
import { apiClient } from "../lib/api/client";
3
import { FOLLOW_CONFIG } from "../config/constants";
4
import { getAtprotoApp } from "../lib/utils/platform";
···
15
const [isFollowing, setIsFollowing] = useState(false);
16
const [isCheckingFollowStatus, setIsCheckingFollowStatus] = useState(false);
17
18
+
const followSelectedUsers = useCallback(async (
19
onUpdate: (message: string) => void,
20
+
): Promise<void> => {
21
if (!session || isFollowing) return;
22
23
const destinationApp = getAtprotoApp(destinationAppId);
···
156
} finally {
157
setIsFollowing(false);
158
}
159
+
}, [session, searchResults, setSearchResults, destinationAppId, isFollowing]);
160
161
return {
162
isFollowing,
+22
-20
src/hooks/useSearch.ts
+22
-20
src/hooks/useSearch.ts
···
1
-
import { useState } from "react";
2
import { apiClient } from "../lib/api/client";
3
import { SEARCH_CONFIG } from "../config/constants";
4
import type { SearchResult, SearchProgress, AtprotoSession } from "../types";
···
15
new Set(),
16
);
17
18
-
async function searchAllUsers(
19
resultsToSearch: SearchResult[],
20
onProgressUpdate: (message: string) => void,
21
onComplete: () => void,
22
followLexicon?: string,
23
-
) {
24
if (!session || resultsToSearch.length === 0) return;
25
26
setIsSearchingAll(true);
···
133
`Search complete! Found ${totalFound} matches out of ${totalSearched} users searched.`,
134
);
135
onComplete();
136
-
}
137
138
-
function toggleMatchSelection(resultIndex: number, did: string) {
139
setSearchResults((prev) => {
140
// Only update the specific item instead of mapping entire array
141
const newResults = [...prev];
···
151
newResults[resultIndex] = { ...result, selectedMatches: newSelectedMatches };
152
return newResults;
153
});
154
-
}
155
156
-
function toggleExpandResult(index: number) {
157
setExpandedResults((prev) => {
158
const next = new Set(prev);
159
if (next.has(index)) next.delete(index);
160
else next.add(index);
161
return next;
162
});
163
-
}
164
165
-
function selectAllMatches(onUpdate: (message: string) => void) {
166
-
setSearchResults((prev) =>
167
-
prev.map((result) => {
168
const newSelectedMatches = new Set<string>();
169
if (result.atprotoMatches.length > 0) {
170
newSelectedMatches.add(result.atprotoMatches[0].did);
···
173
...result,
174
selectedMatches: newSelectedMatches,
175
};
176
-
}),
177
-
);
178
179
-
const totalToSelect = searchResults.filter(
180
-
(r) => r.atprotoMatches.length > 0,
181
-
).length;
182
-
onUpdate(`Selected ${totalToSelect} top matches`);
183
-
}
184
185
-
function deselectAllMatches(onUpdate: (message: string) => void) {
186
setSearchResults((prev) =>
187
prev.map((result) => ({
188
...result,
···
190
})),
191
);
192
onUpdate("Cleared all selections");
193
-
}
194
195
const totalSelected = searchResults.reduce(
196
(total, result) => total + (result.selectedMatches?.size || 0),
···
1
+
import { useState, useCallback } from "react";
2
import { apiClient } from "../lib/api/client";
3
import { SEARCH_CONFIG } from "../config/constants";
4
import type { SearchResult, SearchProgress, AtprotoSession } from "../types";
···
15
new Set(),
16
);
17
18
+
const searchAllUsers = useCallback(async (
19
resultsToSearch: SearchResult[],
20
onProgressUpdate: (message: string) => void,
21
onComplete: () => void,
22
followLexicon?: string,
23
+
) => {
24
if (!session || resultsToSearch.length === 0) return;
25
26
setIsSearchingAll(true);
···
133
`Search complete! Found ${totalFound} matches out of ${totalSearched} users searched.`,
134
);
135
onComplete();
136
+
}, [session]);
137
138
+
const toggleMatchSelection = useCallback((resultIndex: number, did: string) => {
139
setSearchResults((prev) => {
140
// Only update the specific item instead of mapping entire array
141
const newResults = [...prev];
···
151
newResults[resultIndex] = { ...result, selectedMatches: newSelectedMatches };
152
return newResults;
153
});
154
+
}, []);
155
156
+
const toggleExpandResult = useCallback((index: number) => {
157
setExpandedResults((prev) => {
158
const next = new Set(prev);
159
if (next.has(index)) next.delete(index);
160
else next.add(index);
161
return next;
162
});
163
+
}, []);
164
165
+
const selectAllMatches = useCallback((onUpdate: (message: string) => void) => {
166
+
setSearchResults((prev) => {
167
+
const updated = prev.map((result) => {
168
const newSelectedMatches = new Set<string>();
169
if (result.atprotoMatches.length > 0) {
170
newSelectedMatches.add(result.atprotoMatches[0].did);
···
173
...result,
174
selectedMatches: newSelectedMatches,
175
};
176
+
});
177
178
+
const totalToSelect = updated.filter(
179
+
(r) => r.atprotoMatches.length > 0,
180
+
).length;
181
+
onUpdate(`Selected ${totalToSelect} top matches`);
182
+
183
+
return updated;
184
+
});
185
+
}, []);
186
187
+
const deselectAllMatches = useCallback((onUpdate: (message: string) => void) => {
188
setSearchResults((prev) =>
189
prev.map((result) => ({
190
...result,
···
192
})),
193
);
194
onUpdate("Cleared all selections");
195
+
}, []);
196
197
const totalSelected = searchResults.reduce(
198
(total, result) => total + (result.selectedMatches?.size || 0),