mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import React from 'react'
2import {
3 type AppBskyLabelerDefs,
4 BskyAgent,
5 type ComAtprotoLabelDefs,
6 type InterpretedLabelValueDefinition,
7 LABELS,
8 type ModerationCause,
9 type ModerationOpts,
10 type ModerationUI,
11} from '@atproto/api'
12
13import {sanitizeDisplayName} from '#/lib/strings/display-names'
14import {sanitizeHandle} from '#/lib/strings/handles'
15import {type AppModerationCause} from '#/components/Pills'
16
17export const ADULT_CONTENT_LABELS = ['sexual', 'nudity', 'porn']
18export const OTHER_SELF_LABELS = ['graphic-media']
19export const SELF_LABELS = [...ADULT_CONTENT_LABELS, ...OTHER_SELF_LABELS]
20
21export type AdultSelfLabel = (typeof ADULT_CONTENT_LABELS)[number]
22export type OtherSelfLabel = (typeof OTHER_SELF_LABELS)[number]
23export type SelfLabel = (typeof SELF_LABELS)[number]
24
25export function getModerationCauseKey(
26 cause: ModerationCause | AppModerationCause,
27): string {
28 const source =
29 cause.source.type === 'labeler'
30 ? cause.source.did
31 : cause.source.type === 'list'
32 ? cause.source.list.uri
33 : 'user'
34 if (cause.type === 'label') {
35 return `label:${cause.label.val}:${source}`
36 }
37 return `${cause.type}:${source}`
38}
39
40export function isJustAMute(modui: ModerationUI): boolean {
41 return modui.filters.length === 1 && modui.filters[0].type === 'muted'
42}
43
44export function moduiContainsHideableOffense(modui: ModerationUI): boolean {
45 const label = modui.filters.at(0)
46 if (label && label.type === 'label') {
47 return labelIsHideableOffense(label.label)
48 }
49 return false
50}
51
52export function labelIsHideableOffense(
53 label: ComAtprotoLabelDefs.Label,
54): boolean {
55 return ['!hide', '!takedown'].includes(label.val)
56}
57
58export function getLabelingServiceTitle({
59 displayName,
60 handle,
61}: {
62 displayName?: string
63 handle: string
64}) {
65 return displayName
66 ? sanitizeDisplayName(displayName)
67 : sanitizeHandle(handle, '@')
68}
69
70export function lookupLabelValueDefinition(
71 labelValue: string,
72 customDefs: InterpretedLabelValueDefinition[] | undefined,
73): InterpretedLabelValueDefinition | undefined {
74 let def
75 if (!labelValue.startsWith('!') && customDefs) {
76 def = customDefs.find(d => d.identifier === labelValue)
77 }
78 if (!def) {
79 def = LABELS[labelValue as keyof typeof LABELS]
80 }
81 return def
82}
83
84export function isAppLabeler(
85 labeler:
86 | string
87 | AppBskyLabelerDefs.LabelerView
88 | AppBskyLabelerDefs.LabelerViewDetailed,
89): boolean {
90 if (typeof labeler === 'string') {
91 return BskyAgent.appLabelers.includes(labeler)
92 }
93 return BskyAgent.appLabelers.includes(labeler.creator.did)
94}
95
96export function isLabelerSubscribed(
97 labeler:
98 | string
99 | AppBskyLabelerDefs.LabelerView
100 | AppBskyLabelerDefs.LabelerViewDetailed,
101 modOpts: ModerationOpts,
102) {
103 labeler = typeof labeler === 'string' ? labeler : labeler.creator.did
104 if (isAppLabeler(labeler)) {
105 return true
106 }
107 return modOpts.prefs.labelers.find(l => l.did === labeler)
108}
109
110export type Subject =
111 | {
112 uri: string
113 cid: string
114 }
115 | {
116 did: string
117 }
118
119export function useLabelSubject({label}: {label: ComAtprotoLabelDefs.Label}): {
120 subject: Subject
121} {
122 return React.useMemo(() => {
123 const {cid, uri} = label
124 if (cid) {
125 return {
126 subject: {
127 uri,
128 cid,
129 },
130 }
131 } else {
132 return {
133 subject: {
134 did: uri,
135 },
136 }
137 }
138 }, [label])
139}
140
141export function unique(
142 value: ModerationCause,
143 index: number,
144 array: ModerationCause[],
145) {
146 return (
147 array.findIndex(
148 item => getModerationCauseKey(item) === getModerationCauseKey(value),
149 ) === index
150 )
151}