tangled
alpha
login
or
join now
byarielm.fyi
/
atlast
16
fork
atom
ATlast — you'll never need to find your favorites on another platform again. Find your favs in the ATmosphere.
atproto
16
fork
atom
overview
issues
1
pulls
pipelines
fix: prevent duplicate file upload
byarielm.fyi
4 months ago
5388e077
e6552c3f
+40
-9
2 changed files
expand all
collapse all
unified
split
netlify
functions
save-results.ts
src
App.tsx
+19
netlify/functions/save-results.ts
···
35
35
}
36
36
37
37
export const handler: Handler = async (event: HandlerEvent): Promise<HandlerResponse> => {
38
38
+
38
39
if (event.httpMethod !== 'POST') {
39
40
return {
40
41
statusCode: 405,
···
80
81
81
82
const sql = getDbClient();
82
83
let matchedCount = 0;
84
84
+
85
85
+
// Check for recent uploads from this user
86
86
+
const recentUpload = await sql`
87
87
+
SELECT upload_id FROM user_uploads
88
88
+
WHERE did = ${userSession.did}
89
89
+
AND created_at > NOW() - INTERVAL '5 seconds'
90
90
+
ORDER BY created_at DESC
91
91
+
LIMIT 1
92
92
+
`;
93
93
+
94
94
+
if ((recentUpload as any[]).length > 0) {
95
95
+
console.log(`User ${userSession.did} already saved within 5 seconds, skipping duplicate`);
96
96
+
return {
97
97
+
statusCode: 200,
98
98
+
headers: { 'Content-Type': 'application/json' },
99
99
+
body: JSON.stringify({ success: true, message: 'Recently saved' }),
100
100
+
};
101
101
+
}
83
102
84
103
// IMPORTANT: Create upload record FIRST before processing results
85
104
// This is required because user_source_follows has a foreign key to user_uploads
+21
-9
src/App.tsx
···
1
1
-
import { useState } from "react";
1
1
+
import { useState, useRef } from "react";
2
2
import { ArrowRight } from "lucide-react";
3
3
import LoginPage from "./pages/Login";
4
4
import HomePage from "./pages/Home";
···
24
24
25
25
// Add state to track current platform
26
26
const [currentPlatform, setCurrentPlatform] = useState<string>('tiktok');
27
27
+
const saveCalledRef = useRef(false);
27
28
28
29
// Search hook
29
30
const {
···
66
67
setStatusMessage,
67
68
() => {
68
69
setCurrentStep('results');
69
69
-
setSearchResults(currentResults => {
70
70
-
const uploadId = crypto.randomUUID();
71
71
-
apiClient.saveResults(uploadId, platform, currentResults).catch(err => {
72
72
-
console.error('Background save failed:', err);
73
73
-
});
74
74
-
return currentResults;
75
75
-
});
70
70
+
// Prevent duplicate saves
71
71
+
if (!saveCalledRef.current) {
72
72
+
saveCalledRef.current = true;
73
73
+
// Need to wait for React to finish updating searchResults state
74
74
+
// Use a longer delay and access via setSearchResults callback to get final state
75
75
+
setTimeout(() => {
76
76
+
setSearchResults(currentResults => {
77
77
+
if (currentResults.length > 0) {
78
78
+
const uploadId = crypto.randomUUID();
79
79
+
apiClient.saveResults(uploadId, platform, currentResults).catch(err => {
80
80
+
console.error('Background save failed:', err);
81
81
+
});
82
82
+
}
83
83
+
return currentResults; // Don't modify, just return as-is
84
84
+
});
85
85
+
}, 1000); // Longer delay to ensure all state updates complete
86
86
+
}
76
87
}
77
88
);
78
89
},
···
97
108
98
109
const platform = 'tiktok'; // Default, will be updated when we add platform to upload details
99
110
setCurrentPlatform(platform);
100
100
-
111
111
+
saveCalledRef.current = false;
112
112
+
101
113
// Convert the loaded results to SearchResult format with selectedMatches
102
114
const loadedResults = data.results.map(result => ({
103
115
...result,