swadhinbiswas Initial release v0.1.0 · 1/16/2026
ed7a4e4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
export interface WatchedThread {
id: number;
board: string;
title: string;
lastChecked: number;
lastReplyCount: number;
hasNewReplies: boolean;
}
interface WatchlistState {
watchedThreads: WatchedThread[];
// Actions
watchThread: (thread: Omit<WatchedThread, 'lastChecked' | 'hasNewReplies'>) => void;
unwatchThread: (id: number) => void;
updateThreadStatus: (id: number, replyCount: number) => void;
markThreadAsRead: (id: number) => void;
clearWatchlist: () => void;
}
export const useWatchlistStore = create<WatchlistState>()(
persist(
(set) => ({
watchedThreads: [],
watchThread: (thread) => {
set((state) => {
// Check if already watching
if (state.watchedThreads.some((t) => t.id === thread.id)) {
return state;
}
return {
watchedThreads: [
...state.watchedThreads,
{
...thread,
lastChecked: Date.now(),
hasNewReplies: false,
},
],
};
});
},
unwatchThread: (id) => {
set((state) => ({
watchedThreads: state.watchedThreads.filter((t) => t.id !== id),
}));
},
updateThreadStatus: (id, replyCount) => {
set((state) => ({
watchedThreads: state.watchedThreads.map((t) => {
if (t.id === id) {
return {
...t,
lastChecked: Date.now(),
hasNewReplies: replyCount > t.lastReplyCount,
lastReplyCount: replyCount,
};
}
return t;
}),
}));
},
markThreadAsRead: (id) => {
set((state) => ({
watchedThreads: state.watchedThreads.map((t) =>
t.id === id ? { ...t, hasNewReplies: false } : t
),
}));
},
clearWatchlist: () => {
set({ watchedThreads: [] });
},
}),
{
name: 'watchlist-storage',
}
)
);