/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see .
*/
import {Trans, useLingui} from '@lingui/react/macro';
import {ClockIcon, XCircleIcon} from '@phosphor-icons/react';
import {observer} from 'mobx-react-lite';
import React from 'react';
import * as GuildMemberActionCreators from '~/actions/GuildMemberActionCreators';
import * as ModalActionCreators from '~/actions/ModalActionCreators';
import {modal} from '~/actions/ModalActionCreators';
import * as ToastActionCreators from '~/actions/ToastActionCreators';
import {
MenuBottomSheet,
type MenuGroupType,
type MenuItemType,
type MenuRadioType,
} from '~/components/uikit/MenuBottomSheet/MenuBottomSheet';
import type {GuildMemberRecord} from '~/records/GuildMemberRecord';
import type {UserRecord} from '~/records/UserRecord';
import {RemoveTimeoutModal} from './RemoveTimeoutModal';
import {getTimeoutDurationOptions, type TimeoutDurationOption} from './TimeoutMemberOptions';
import styles from './TimeoutMemberSheet.module.css';
interface TimeoutMemberSheetProps {
isOpen: boolean;
onClose: () => void;
guildId: string;
targetUser: UserRecord;
targetMember: GuildMemberRecord;
}
export const TimeoutMemberSheet: React.FC = observer(
({isOpen, onClose, guildId, targetUser, targetMember}) => {
const {t} = useLingui();
const isCurrentlyTimedOut = targetMember.isTimedOut();
const timeoutOptions = React.useMemo(() => getTimeoutDurationOptions(t), [t]);
const [timeoutDuration, setTimeoutDuration] = React.useState(timeoutOptions[3].value);
const [isSubmitting, setIsSubmitting] = React.useState(false);
const handleTimeout = React.useCallback(async () => {
setIsSubmitting(true);
try {
const timeoutUntil = new Date(Date.now() + timeoutDuration * 1000).toISOString();
await GuildMemberActionCreators.timeout(guildId, targetUser.id, timeoutUntil);
ToastActionCreators.createToast({
type: 'success',
children: Successfully timed out {targetUser.tag},
});
onClose();
} catch (error) {
console.error('Failed to timeout member:', error);
ToastActionCreators.createToast({
type: 'error',
children: Failed to timeout member. Please try again.,
});
} finally {
setIsSubmitting(false);
}
}, [guildId, onClose, targetUser.id, timeoutDuration, targetUser.tag]);
const durationItems: Array = React.useMemo(() => {
return timeoutOptions.map((option: TimeoutDurationOption) => ({
label: option.label,
selected: option.value === timeoutDuration,
onSelect: () => setTimeoutDuration(option.value),
}));
}, [timeoutDuration, timeoutOptions]);
const actionItems: Array = React.useMemo(() => {
const items: Array = [
{
id: 'timeout',
icon: ,
label: t`Timeout`,
onClick: handleTimeout,
danger: true,
disabled: isSubmitting,
},
];
if (isCurrentlyTimedOut) {
items.push({
id: 'remove-timeout',
icon: ,
label: t`Remove Timeout`,
onClick: () => {
onClose();
ModalActionCreators.push(modal(() => ));
},
danger: true,
disabled: isSubmitting,
});
}
return items;
}, [guildId, handleTimeout, isCurrentlyTimedOut, isSubmitting, onClose, targetUser]);
const headerContent = (
{isCurrentlyTimedOut ? (
{targetUser.tag} is currently timed out. You can update their timeout duration or remove
the timeout.
) : (
Prevent {targetUser.tag} from sending messages, reacting, and connecting to voice
channels for the specified duration.
)}