diff --git a/app/actions/ModActionPanel/BlobList.tsx b/app/actions/ModActionPanel/BlobList.tsx index f21d41b5..181eea5e 100644 --- a/app/actions/ModActionPanel/BlobList.tsx +++ b/app/actions/ModActionPanel/BlobList.tsx @@ -23,7 +23,7 @@ export function BlobList(props: { const displayActionType = subjectStatus?.takendown ? 'Taken down' : '' return (
-
+
@@ -654,6 +664,12 @@ function Form( /> )} + {submission.error && ( +
+ +
+ )} +
(C)ancel @@ -674,14 +690,14 @@ function Form( (S)ubmit @@ -705,14 +721,14 @@ function Form(
navigateQueue(-1)} - disabled={submitting} + disabled={submission.isSubmitting} > navigateQueue(1)} - disabled={submitting} + disabled={submission.isSubmitting} > diff --git a/components/common/Card.tsx b/components/common/Card.tsx new file mode 100644 index 00000000..c0d0a8e6 --- /dev/null +++ b/components/common/Card.tsx @@ -0,0 +1,19 @@ +import React from 'react' + +export type Variation = 'default' | 'error' + +export const Card = ({ + children, + variation = 'default', +}: { + children: React.ReactNode + variation?: Variation +}) => { + let className = 'shadow rounded-sm p-2' + if (variation === 'error') { + className += ' bg-red-100 dark:bg-red-600 border-red-400 text-red-700 dark:text-red-100' + } else { + className += ' dark:shadow-slate-700 bg-white dark:bg-slate-800' + } + return
{children}
+} diff --git a/components/common/labels/Grid.tsx b/components/common/labels/Grid.tsx index 01715d19..55b75e9c 100644 --- a/components/common/labels/Grid.tsx +++ b/components/common/labels/Grid.tsx @@ -2,7 +2,6 @@ import { useState } from 'react' import Select from 'react-tailwindcss-select' import { labelOptions, - displayLabel, groupLabelList, getLabelGroupInfo, buildAllLabelOptions, diff --git a/components/common/labels/Input.tsx b/components/common/labels/Input.tsx deleted file mode 100644 index c78e3b62..00000000 --- a/components/common/labels/Input.tsx +++ /dev/null @@ -1,151 +0,0 @@ -import { Fragment } from 'react' -import { Popover, Transition } from '@headlessui/react' -import { useSyncedState } from '@/lib/useSyncedState' -import { LabelChip, LabelList, LabelListEmpty } from './List' -import { - labelOptions, - displayLabel, - groupLabelList, - getLabelGroupInfo, - buildAllLabelOptions, - isSelfLabel, - unFlagSelfLabel, -} from './util' -import { classNames } from '@/lib/util' - -const EMPTY_ARR = [] - -export function LabelsInput(props: LabelsProps) { - const { - id, - formId, - name, - className = '', - defaultLabels = EMPTY_ARR, - options = labelOptions, - disabled, - ...others - } = props - const allOptions = buildAllLabelOptions(defaultLabels, options) - const [packedCurrent, setPackedCurrent] = useSyncedState( - packMemo(defaultLabels), - ) - const current = unpackMemo(packedCurrent) - const groupedLabelList = groupLabelList(allOptions) - - return ( - - - {!current.length && (click to add)} - {current.map((label) => { - const labelGroup = getLabelGroupInfo(unFlagSelfLabel(label)) - return ( - - {displayLabel(label)} - - - ) - })} - - { - const form = document.getElementById(formId) as HTMLFormElement - if (!form) throw new Error(`Form with id ${formId} doesn't exist`) - const nextLabels = new FormData(form) - .getAll(`${name}-staged`) - .map((val) => String(val)) - setPackedCurrent(packMemo(nextLabels)) - }} - > - -
-
- {Object.values(groupedLabelList).map((group, groupIndex) => { - const groupTitle = group.strings.settings.en.name - return ( -
-

- {groupTitle} -

-
- {group.labels.map((opt, i) => { - const labelText = typeof opt === 'string' ? opt : opt.id - const cantChange = isSelfLabel(labelText) - return ( -
-
- -
- -
- ) - })} -
-
- ) - })} -
-
-
-
-
- ) -} - -type LabelsProps = { - id: string - formId: string - name: string - disabled?: boolean - className?: string - defaultLabels?: string[] - options?: string[] -} - -function packMemo(val: unknown) { - return JSON.stringify(val) -} - -function unpackMemo(memo: string) { - return JSON.parse(memo) as T -} diff --git a/components/common/labels/index.ts b/components/common/labels/index.ts index 83e657cd..26ea7451 100644 --- a/components/common/labels/index.ts +++ b/components/common/labels/index.ts @@ -1,3 +1,2 @@ -export * from './Input' export * from './List' export * from './util' diff --git a/components/common/posts/PostsFeed.tsx b/components/common/posts/PostsFeed.tsx index b0c69729..3455a1ad 100644 --- a/components/common/posts/PostsFeed.tsx +++ b/components/common/posts/PostsFeed.tsx @@ -23,9 +23,10 @@ import { RichText } from '../RichText' import { LabelChip, LabelList, - getLabelGroupInfo, doesLabelNeedBlur, toLabelVal, + LabelGroupInfo, + getLabelGroupInfo, } from '../labels' import { CollectionId } from '@/reports/helpers/subject' import { ProfileAvatar } from '@/repositories/ProfileAvatar' @@ -354,7 +355,10 @@ function PostEmbeds({ item }: { item: AppBskyFeedDefs.FeedViewPost }) {

The author of the original post blocked the author.{' '} - + See quoted post {' ยท '} @@ -415,10 +419,11 @@ function PostLabels({ {labels?.map((label, i) => { const { val, src } = label const labelGroup = getLabelGroupInfo(val) - return ( { return ( -

+

By{' '} @@ -45,7 +46,7 @@ const Comment = ({ header="Removed: " labels={modEvent.event.negateLabelVals as string[] | undefined} /> -

+ ) } @@ -57,7 +58,7 @@ const Email = ({ } }) => { return ( -
+

By{' '} {modEvent.creatorHandle @@ -68,7 +69,7 @@ const Email = ({

Subject: {modEvent.event.subjectLine}

)} {modEvent.event.comment &&

{modEvent.event.comment}

} -
+ ) } @@ -82,7 +83,7 @@ const Report = ({ const isAppeal = modEvent.event.reportType === ComAtprotoModerationDefs.REASONAPPEAL return ( -
+

By{' '} @@ -97,7 +98,7 @@ const Report = ({ {modEvent.event.comment && (

{modEvent.event.comment}

)} -
+ ) } @@ -112,7 +113,7 @@ const TakedownOrMute = ({ }) => { const expiresAt = getExpiresAtFromEvent(modEvent) return ( -
+

By{' '} @@ -141,7 +142,7 @@ const TakedownOrMute = ({ header="Removed: " labels={modEvent.event.negateLabelVals as string[] | undefined} /> -

+ ) } @@ -176,7 +177,7 @@ const Label = ({ } & ComAtprotoAdminDefs.ModEventView }) => { return ( -
+

By{' '} @@ -190,7 +191,7 @@ const Label = ({ ) : null} -

+ ) } @@ -202,7 +203,7 @@ const Tag = ({ } & ComAtprotoAdminDefs.ModEventView }) => { return ( -
+

By{' '} @@ -216,7 +217,7 @@ const Tag = ({ ) : null} -

+ ) } @@ -250,7 +251,9 @@ export const ModEventItem = ({ ComAtprotoAdminDefs.isModEventComment(modEvent.event) || ComAtprotoAdminDefs.isModEventUnmute(modEvent.event) || ComAtprotoAdminDefs.isModEventResolveAppeal(modEvent.event) || - ComAtprotoAdminDefs.isModEventReverseTakedown(modEvent.event) + ComAtprotoAdminDefs.isModEventReverseTakedown(modEvent.event) || + // This is temporary since the api package with this new type check is not yet published + modEvent.event.$type === 'com.atproto.admin.defs#modEventDivert' ) { eventItem = } diff --git a/components/mod-event/SelectorButton.tsx b/components/mod-event/SelectorButton.tsx index 6f696d46..42387a76 100644 --- a/components/mod-event/SelectorButton.tsx +++ b/components/mod-event/SelectorButton.tsx @@ -28,6 +28,10 @@ const actions = [ text: 'Resolve Appeal', key: MOD_EVENTS.RESOLVE_APPEAL, }, + { + text: 'Divert', + key: MOD_EVENTS.DIVERT, + }, ] const actionsByKey = actions.reduce((acc, action) => { acc[action.key] = action.text @@ -38,10 +42,12 @@ export const ModEventSelectorButton = ({ subjectStatus, selectedAction, setSelectedAction, + hasBlobs, }: { subjectStatus?: ComAtprotoAdminDefs.SubjectStatusView | null selectedAction: string setSelectedAction: (action: string) => void + hasBlobs: boolean }) => { const availableActions = useMemo(() => { return actions.filter(({ key, text }) => { @@ -58,7 +64,14 @@ export const ModEventSelectorButton = ({ return false } // Don't show takedown action if subject is already takendown - if (key === MOD_EVENTS.TAKEDOWN && subjectStatus?.takendown) { + if ( + (key === MOD_EVENTS.TAKEDOWN || key === MOD_EVENTS.DIVERT) && + subjectStatus?.takendown + ) { + return false + } + // Don't show divert action if the subject does not have any blobs + if (key === MOD_EVENTS.DIVERT && !hasBlobs) { return false } // Don't show reverse takedown action if subject is not takendown @@ -88,6 +101,7 @@ export const ModEventSelectorButton = ({ subjectStatus?.muteUntil, subjectStatus?.reviewState, subjectStatus?.appealed, + hasBlobs, ]) return ( { + if (ActionErrors[error]) { + return ( + +

{ActionErrors[error].title}

+

{ActionErrors[error].description}

+
+ ) + } + return ( + +

{error}

+
+ ) +}