5180 fichiers 38.5 Mo 0 téléchargements 479 vues mis à jour il y a 7 heures ui
nitro-v36-with-renderer-v36 / src / components / housekeeping / views / hotel / HousekeepingHotelAlertView.tsx
HousekeepingHotelAlertView.tsx 4.8 Ko Télécharger le fichier
import { FC, ReactNode, useState } from 'react';
import { FaBullhorn, FaDoorOpen, FaGlobe, FaUser, FaUserShield } from 'react-icons/fa';
import { buildHousekeepingAlertRecipient, HOUSEKEEPING_ALERT_SCOPES, HousekeepingAlertScope, LocalizeText } from '../../../../api';
import { NativeTextTree } from '../../../../common/native-text/NativeTextTree';
import { useHousekeeping, useHousekeepingConfirm } from '../../../../hooks';
import { HOUSEKEEPING_INPUT_CLASS, HousekeepingButton, HousekeepingSection } from '../common/HousekeepingParts';
import { HousekeepingSubTabs } from '../common/HousekeepingSubTabs';

const HOTEL_ALERT_MAX = 1000;

const SCOPE_ICONS: Record<HousekeepingAlertScope, ReactNode> = {
    hotel: <FaGlobe size={9} />,
    user: <FaUser size={9} />,
    room: <FaDoorOpen size={9} />,
    staff: <FaUserShield size={9} />
};

/** An alert to the whole hotel, one online user, the users of one room, or the staff. */
export const HousekeepingHotelAlertView: FC = () => {
    const { isActionPending, sendHotelAlert } = useHousekeeping();
    const confirm = useHousekeepingConfirm();
    const [scope, setScope] = useState<HousekeepingAlertScope>('hotel');
    const [target, setTarget] = useState('');
    const [alertText, setAlertText] = useState('');
    const trimmedAlert = alertText.trim();
    const recipient = buildHousekeepingAlertRecipient(scope, target);
    const needsTarget = scope === 'user' || scope === 'room';

    const send = () => {
        if (recipient === null) return;

        const dispatch = async () => {
            const result = await sendHotelAlert(trimmedAlert, recipient);

            if (result?.ok) setAlertText('');
        };

        // A long alert to everyone is the one worth a second look.
        // Every hotel-wide alert is confirmed: a short test line sent with the default scope used to reach everyone.
        if (scope === 'hotel') {
            confirm(LocalizeText('housekeeping.hotel.alert.confirm', ['count'], [String(trimmedAlert.length)]), dispatch);

            return;
        }

        dispatch();
    };

    return (
        <NativeTextTree>
            <HousekeepingSection icon={<FaBullhorn className="text-rose-500" size={9} />} title={LocalizeText('housekeeping.hotel.alert.label')} tone="danger">
                <HousekeepingSubTabs
                    compact
                    active={scope}
                    tabs={HOUSEKEEPING_ALERT_SCOPES.map((id) => ({ id, icon: SCOPE_ICONS[id], label: LocalizeText(`housekeeping.hotel.alert.scope.${id}`) }))}
                    onChange={(id) => {
                        setScope(id);
                        setTarget('');
                    }}
                />
                {needsTarget && (
                    <input
                        className={HOUSEKEEPING_INPUT_CLASS}
                        inputMode={scope === 'room' ? 'numeric' : 'text'}
                        placeholder={LocalizeText(`housekeeping.hotel.alert.target.${scope}`)}
                        value={target}
                        onChange={(event) => setTarget(event.target.value)}
                    />
                )}
                <textarea
                    className={`${HOUSEKEEPING_INPUT_CLASS} min-h-[90px] resize-y`}
                    maxLength={HOTEL_ALERT_MAX}
                    placeholder={LocalizeText('housekeeping.hotel.alert.placeholder')}
                    value={alertText}
                    onChange={(event) => setAlertText(event.target.value)}
                />
                <div className="flex items-center gap-1.5">
                    <span className="text-[10px] tabular-nums text-zinc-500">
                        {trimmedAlert.length}/{HOTEL_ALERT_MAX}
                    </span>
                    <HousekeepingButton
                        classNames={['ml-auto']}
                        disabled={isActionPending || !trimmedAlert.length || recipient === null}
                        gap={1}
                        variant="danger"
                        onClick={send}
                    >
                        <FaBullhorn size={10} />
                        <span>{LocalizeText(`housekeeping.hotel.alert.send.${scope}`)}</span>
                    </HousekeepingButton>
                </div>
                {trimmedAlert.length > 0 && (
                    <div className="rounded border border-zinc-200 bg-white p-2 text-xs text-zinc-800">
                        <div className="mb-1 text-[9px] font-semibold uppercase tracking-wide text-zinc-500">
                            {LocalizeText('housekeeping.hotel.alert.preview')}
                        </div>
                        <div className="whitespace-pre-wrap break-words">{trimmedAlert}</div>
                    </div>
                )}
            </HousekeepingSection>
        </NativeTextTree>
    );
};
15Sujets
1Dépôts
20Membres
3En ligne
Profile
Inscrit
Dernière visite
Messages
0
Votes positifs
0
Votes négatifs
0

Nous utilisons des cookies pour assurer le bon fonctionnement du site et améliorer votre expérience. en savoir plus

Autoriser