tangled
alpha
login
or
join now
xan.lol
/
flushes.app
forked from
atpota.to/flushes.app
0
fork
atom
The 1st decentralized social network for sharing when you're on the toilet. Post a "flush" today! Powered by the AT Protocol.
0
fork
atom
overview
issues
pulls
pipelines
fix
dame-is
3 months ago
c8b5a3a6
64f4a17e
+155
-3
2 changed files
expand all
collapse all
unified
split
src
app
page.module.css
page.tsx
+33
src/app/page.module.css
···
533
533
min-width: 0;
534
534
}
535
535
536
536
+
.contentRight {
537
537
+
display: flex;
538
538
+
align-items: center;
539
539
+
gap: 0.75rem;
540
540
+
margin-left: auto;
541
541
+
}
542
542
+
543
543
+
.editButton {
544
544
+
background: none;
545
545
+
border: 1px solid var(--tile-border);
546
546
+
color: var(--text-color);
547
547
+
padding: 6px;
548
548
+
cursor: pointer;
549
549
+
display: flex;
550
550
+
align-items: center;
551
551
+
justify-content: center;
552
552
+
transition: all 0.2s;
553
553
+
width: 32px;
554
554
+
height: 32px;
555
555
+
border-radius: 4px;
556
556
+
}
557
557
+
558
558
+
.editButton svg {
559
559
+
width: 16px;
560
560
+
height: 16px;
561
561
+
}
562
562
+
563
563
+
.editButton:hover {
564
564
+
border-color: var(--primary-color);
565
565
+
color: var(--primary-color);
566
566
+
background: rgba(91, 173, 240, 0.05);
567
567
+
}
568
568
+
536
569
.userLine {
537
570
display: flex;
538
571
align-items: center;
+122
-3
src/app/page.tsx
···
7
7
import { useAuth } from '@/lib/auth-context';
8
8
import { containsBannedWords, sanitizeText, isAllowedEmoji } from '@/lib/content-filter';
9
9
import { formatRelativeTime } from '@/lib/time-utils';
10
10
+
import EditFlushModal from '@/components/EditFlushModal';
10
11
11
12
// Types for feed entries
12
13
interface FlushingEntry {
···
39
40
const [loading, setLoading] = useState(true);
40
41
const [error, setError] = useState<string | null>(null);
41
42
const [newEntryIds, setNewEntryIds] = useState<Set<string>>(new Set());
43
43
+
const [editingFlush, setEditingFlush] = useState<FlushingEntry | null>(null);
44
44
+
const [actionError, setActionError] = useState<string | null>(null);
45
45
+
const [actionSuccess, setActionSuccess] = useState<string | null>(null);
42
46
43
47
useEffect(() => {
44
48
// Fetch the latest entries when the component mounts
···
306
310
await signOut();
307
311
};
308
312
313
313
+
// Check if the current user owns this flush
314
314
+
const isOwnFlush = (authorDid: string) => {
315
315
+
if (!session) return false;
316
316
+
return session.sub === authorDid;
317
317
+
};
318
318
+
319
319
+
// Handle updating a flush
320
320
+
const handleUpdateFlush = async (text: string, emoji: string) => {
321
321
+
if (!session || !editingFlush) {
322
322
+
setActionError('You must be logged in to update a flush');
323
323
+
return;
324
324
+
}
325
325
+
326
326
+
try {
327
327
+
setActionError(null);
328
328
+
setActionSuccess(null);
329
329
+
330
330
+
const { updateFlushRecord } = await import('@/lib/api-client');
331
331
+
332
332
+
await updateFlushRecord(
333
333
+
session,
334
334
+
editingFlush.uri,
335
335
+
text,
336
336
+
emoji,
337
337
+
editingFlush.createdAt
338
338
+
);
339
339
+
340
340
+
setActionSuccess('Flush updated successfully!');
341
341
+
342
342
+
// Update the local state
343
343
+
setEntries(entries.map(entry =>
344
344
+
entry.uri === editingFlush.uri
345
345
+
? { ...entry, text, emoji }
346
346
+
: entry
347
347
+
));
348
348
+
349
349
+
// Clear success message after 3 seconds
350
350
+
setTimeout(() => setActionSuccess(null), 3000);
351
351
+
} catch (error: any) {
352
352
+
console.error('Error updating flush:', error);
353
353
+
setActionError(error.message || 'Failed to update flush');
354
354
+
}
355
355
+
};
356
356
+
357
357
+
// Handle deleting a flush
358
358
+
const handleDeleteFlush = async () => {
359
359
+
if (!session || !editingFlush) {
360
360
+
setActionError('You must be logged in to delete a flush');
361
361
+
return;
362
362
+
}
363
363
+
364
364
+
try {
365
365
+
setActionError(null);
366
366
+
setActionSuccess(null);
367
367
+
368
368
+
const { deleteFlushRecord } = await import('@/lib/api-client');
369
369
+
370
370
+
await deleteFlushRecord(session, editingFlush.uri);
371
371
+
372
372
+
setActionSuccess('Flush deleted successfully!');
373
373
+
374
374
+
// Remove from local state
375
375
+
setEntries(entries.filter(entry => entry.uri !== editingFlush.uri));
376
376
+
377
377
+
// Clear success message after 3 seconds
378
378
+
setTimeout(() => setActionSuccess(null), 3000);
379
379
+
} catch (error: any) {
380
380
+
console.error('Error deleting flush:', error);
381
381
+
setActionError(error.message || 'Failed to delete flush');
382
382
+
}
383
383
+
};
384
384
+
309
385
// List of emojis for status selection
310
386
const EMOJIS = [
311
387
'🚽', '🧻', '💩', '💨', '🚾', '🧼', '🪠', '🚻', '🩸', '💧', '💦', '😌',
···
315
391
316
392
return (
317
393
<div className={styles.container}>
394
394
+
395
395
+
{/* Action messages */}
396
396
+
{actionError && (
397
397
+
<div className={styles.error}>
398
398
+
{actionError}
399
399
+
</div>
400
400
+
)}
401
401
+
402
402
+
{actionSuccess && (
403
403
+
<div className={styles.success}>
404
404
+
{actionSuccess}
405
405
+
</div>
406
406
+
)}
407
407
+
408
408
+
{/* Edit Modal */}
409
409
+
<EditFlushModal
410
410
+
isOpen={editingFlush !== null}
411
411
+
flushData={editingFlush ? {
412
412
+
uri: editingFlush.uri,
413
413
+
text: editingFlush.text,
414
414
+
emoji: editingFlush.emoji,
415
415
+
created_at: editingFlush.createdAt
416
416
+
} : null}
417
417
+
onSave={handleUpdateFlush}
418
418
+
onDelete={handleDeleteFlush}
419
419
+
onClose={() => setEditingFlush(null)}
420
420
+
/>
421
421
+
318
422
<header className={styles.header}>
319
423
<div className={styles.headerContent}>
320
424
{/* New header layout with 4 center-aligned lines */}
···
546
650
)}
547
651
</span>
548
652
</div>
549
549
-
<span className={styles.timestamp}>
550
550
-
{formatRelativeTime(entry.createdAt)}
551
551
-
</span>
653
653
+
<div className={styles.contentRight}>
654
654
+
<span className={styles.timestamp}>
655
655
+
{formatRelativeTime(entry.createdAt)}
656
656
+
</span>
657
657
+
{isOwnFlush(entry.authorDid) && isAuthenticated && (
658
658
+
<button
659
659
+
className={styles.editButton}
660
660
+
onClick={() => setEditingFlush(entry)}
661
661
+
aria-label="Edit flush"
662
662
+
title="Edit or delete this flush"
663
663
+
>
664
664
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
665
665
+
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path>
666
666
+
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
667
667
+
</svg>
668
668
+
</button>
669
669
+
)}
670
670
+
</div>
552
671
</div>
553
672
</div>
554
673
))}