Scrapboard.org client
1import { create } from "zustand";
2import { persist } from "zustand/middleware";
3import { moderatePost, ModerationDecision } from "@atproto/api/dist/moderation";
4import { type ModerationOpts } from "@atproto/api/dist/moderation/types";
5import { PostView } from "@atproto/api/dist/client/types/app/bsky/feed/defs";
6
7export interface ModerationState {
8 // Simple content warning preferences
9 showContentWarnings: boolean;
10
11 // Actions
12 setShowContentWarnings: (show: boolean) => void;
13
14 // Helper to get moderation decision using AT Protocol's built-in moderation
15 getModerationDecision: (
16 post: PostView,
17 opts: ModerationOpts
18 ) => ModerationDecision;
19 shouldShowWarning: (post: PostView, opts: ModerationOpts) => boolean;
20}
21
22export const useModerationStore = create<ModerationState>()(
23 persist(
24 (set, get) => ({
25 showContentWarnings: true,
26
27 setShowContentWarnings: (show) => set({ showContentWarnings: show }),
28
29 getModerationDecision: (post: PostView, opts: ModerationOpts) => {
30 return moderatePost(post, opts);
31 },
32
33 shouldShowWarning: (post: PostView, opts: ModerationOpts) => {
34 const state = get();
35 if (!state.showContentWarnings) return false;
36
37 const decision = state.getModerationDecision(post, opts);
38 const ui = decision.ui("contentView");
39
40 // Show warning if content has alerts or informs
41 return ui.alert || ui.inform;
42 },
43 }),
44 {
45 name: "moderation-store",
46 partialize: (state) => ({
47 showContentWarnings: state.showContentWarnings,
48 }),
49 }
50 )
51);