/*
* 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 * as ModalActionCreators from '@app/actions/ModalActionCreators';
import {Message} from '@app/components/channel/Message';
import styles from '@app/components/modals/ConfirmModal.module.css';
import * as Modal from '@app/components/modals/Modal';
import {Button} from '@app/components/uikit/button/Button';
import {MessageRecord} from '@app/records/MessageRecord';
import ChannelStore from '@app/stores/ChannelStore';
import type {ModalProps} from '@app/utils/modals/ModalUtils';
import {MessagePreviewContext} from '@fluxer/constants/src/ChannelConstants';
import {useLingui} from '@lingui/react/macro';
import {observer} from 'mobx-react-lite';
import React, {useCallback, useMemo, useRef, useState} from 'react';
interface ConfirmModalCheckboxProps {
checked?: boolean;
onChange?: (checked: boolean) => void;
}
type ConfirmModalPrimaryVariant = 'primary' | 'danger-primary';
type ConfirmModalProps =
| {
title: React.ReactNode;
description: React.ReactNode;
message?: MessageRecord;
primaryText: React.ReactNode;
primaryVariant?: ConfirmModalPrimaryVariant;
secondaryText?: React.ReactNode | false;
size?: ModalProps['size'];
onPrimary: (checkboxChecked?: boolean) => Promise | void;
onSecondary?: (checkboxChecked?: boolean) => void;
checkboxContent?: React.ReactElement;
}
| {
title: React.ReactNode;
description: React.ReactNode;
message?: MessageRecord;
primaryText?: never;
primaryVariant?: never;
secondaryText?: React.ReactNode | false;
size?: ModalProps['size'];
onPrimary?: never;
onSecondary?: (checkboxChecked?: boolean) => void;
checkboxContent?: React.ReactElement;
};
export const ConfirmModal = observer(
({
title,
description,
message,
primaryText,
primaryVariant = 'danger-primary',
secondaryText,
size = 'small',
onPrimary,
onSecondary,
checkboxContent,
}: ConfirmModalProps) => {
const {t} = useLingui();
const [submitting, setSubmitting] = useState(false);
const [checkboxChecked, setCheckboxChecked] = useState(false);
const initialFocusRef = useRef(null);
const previewBehaviorOverrides = useMemo(
() => ({
isEditing: false,
isHighlight: false,
disableContextMenu: true,
disableContextMenuTracking: true,
contextMenuOpen: false,
}),
[],
);
const messageSnapshot = useMemo(() => {
if (!message) return undefined;
return new MessageRecord(message.toJSON());
}, [message?.id]);
const handlePrimaryClick = useCallback(async () => {
if (!onPrimary) {
return;
}
setSubmitting(true);
try {
await onPrimary(checkboxChecked);
ModalActionCreators.pop();
} finally {
setSubmitting(false);
}
}, [onPrimary, checkboxChecked]);
const handleSecondaryClick = useCallback(() => {
if (onSecondary) {
onSecondary(checkboxChecked);
}
ModalActionCreators.pop();
}, [onSecondary, checkboxChecked]);
return (
{description}
{React.isValidElement(checkboxContent) &&
React.cloneElement(checkboxContent, {
checked: checkboxChecked,
onChange: (value: boolean) => setCheckboxChecked(value),
})}
{messageSnapshot && (