/*
* 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 {CaretDownIcon, CheckIcon} from '@phosphor-icons/react';
import clsx from 'clsx';
import {observer} from 'mobx-react-lite';
import React from 'react';
import * as UserSettingsActionCreators from '~/actions/UserSettingsActionCreators';
import {getStatusTypeLabel, type StatusType, StatusTypes} from '~/Constants';
import {CustomStatusDisplay} from '~/components/common/CustomStatusDisplay/CustomStatusDisplay';
import {CustomStatusBottomSheet} from '~/components/modals/CustomStatusBottomSheet';
import {BottomSheet} from '~/components/uikit/BottomSheet/BottomSheet';
import {StatusIndicator} from '~/components/uikit/StatusIndicator';
import {normalizeCustomStatus} from '~/lib/customStatus';
import PresenceStore from '~/stores/PresenceStore';
import StatusExpiryStore from '~/stores/StatusExpiryStore';
import UserStore from '~/stores/UserStore';
import styles from './StatusChangeBottomSheet.module.css';
const STATUS_ORDER = [StatusTypes.ONLINE, StatusTypes.IDLE, StatusTypes.DND, StatusTypes.INVISIBLE] as const;
const STATUS_DESCRIPTIONS: Record<(typeof STATUS_ORDER)[number], React.ReactNode | null> = {
[StatusTypes.ONLINE]: null,
[StatusTypes.IDLE]: null,
[StatusTypes.DND]: You won't receive notifications on desktop,
[StatusTypes.INVISIBLE]: You'll appear offline,
};
const EXPIRY_OPTIONS = [
{id: 'forever', label: Until I change it, durationMs: null},
{id: '15m', label: 15 minutes, durationMs: 15 * 60 * 1000},
{id: '1h', label: 1 hour, durationMs: 60 * 60 * 1000},
{id: '8h', label: 8 hours, durationMs: 8 * 60 * 60 * 1000},
{id: '24h', label: 24 hours, durationMs: 24 * 60 * 60 * 1000},
{id: '3d', label: 3 days, durationMs: 3 * 24 * 60 * 60 * 1000},
];
const STATUS_SHEET_SNAP_POINTS: Array = [0, 0.75, 1];
interface StatusChangeBottomSheetProps {
isOpen: boolean;
onClose: () => void;
}
interface StatusItemProps {
status: StatusType;
currentStatus: StatusType;
onSelect: (status: StatusType, durationMs: number | null) => void;
}
const StatusItem = observer(({status, currentStatus, onSelect}: StatusItemProps) => {
const {i18n} = useLingui();
const isSelected = currentStatus === status;
const description = STATUS_DESCRIPTIONS[status as keyof typeof STATUS_DESCRIPTIONS];
const hasExpiryOptions = status !== StatusTypes.ONLINE;
const [showExpiry, setShowExpiry] = React.useState(false);
const handleSelect = () => {
if (hasExpiryOptions) {
setShowExpiry(!showExpiry);
} else {
onSelect(status, null);
}
};
const handleExpirySelect = (durationMs: number | null) => {
onSelect(status, durationMs);
setShowExpiry(false);
};
return (