All files / components/dialogs CustomAlert.tsx

92.85% Statements 26/28
71.42% Branches 10/14
93.75% Functions 15/16
95.23% Lines 20/21

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104                                  8x     5x 5x         3x 3x             14x   14x     5x 5x 6x 5x   5x                             2x 2x         1x 1x                           8x 5x       8x                     2x              
/**
 * CustomAlert - 自定义 Alert 组件
 * 用于替代原生 Alert.alert()
 */
 
import React from 'react';
import { ConfirmDialog } from './ConfirmDialog';
import type { AlertConfig } from './types';
import { create } from 'zustand';
 
interface AlertState {
  alerts: (AlertConfig & { id: string; visible: boolean })[];
  showAlert: (config: AlertConfig) => void;
  hideAlert: (id: string) => void;
}
 
// Zustand store for managing alerts
export const useAlertStore = create<AlertState>((set) => ({
  alerts: [],
  showAlert: (config) => {
    const id = `alert-${Date.now()}-${Math.random()}`;
    set((state) => ({
      alerts: [...state.alerts, { ...config, id, visible: true }],
    }));
  },
  hideAlert: (id) => {
    set((state) => ({
      alerts: state.alerts.filter((alert) => alert.id !== id),
    }));
  },
}));
 
// Alert Manager Component
export function AlertManager() {
  const { alerts, hideAlert } = useAlertStore();
 
  return (
    <>
      {alerts.map((alert) => {
        const buttons = alert.buttons || [{ text: '确定', style: 'default' }];
        const hasCancel = buttons.some((btn) => btn.style === 'cancel');
        const primaryButton = buttons.find((btn) => btn.style !== 'cancel');
        const cancelButton = buttons.find((btn) => btn.style === 'cancel');
 
        return (
          <ConfirmDialog
            key={alert.id}
            open={alert.visible}
            onOpenChange={(open) => {
              if (!open) hideAlert(alert.id);
            }}
            title={alert.title}
            message={alert.message}
            type={alert.type}
            icon={alert.icon}
            confirmText={primaryButton?.text || '确定'}
            cancelText={cancelButton?.text || '取消'}
            destructive={primaryButton?.style === 'destructive'}
            onConfirm={async () => {
              await primaryButton?.onPress?.();
              hideAlert(alert.id);
            }}
            onCancel={
              hasCancel
                ? () => {
                    cancelButton?.onPress?.();
                    hideAlert(alert.id);
                  }
                : undefined
            }
            showCloseButton={hasCancel}
            closeOnOverlayClick={hasCancel}
          />
        );
      })}
    </>
  );
}
 
// Helper function to show alert (replaces Alert.alert)
export const showAlert = (config: AlertConfig) => {
  useAlertStore.getState().showAlert(config);
};
 
// Compatibility wrapper for Alert.alert syntax
export const Alert = {
  alert: (
    title: string,
    message?: string,
    buttons?: {
      text: string;
      onPress?: () => void;
      style?: 'default' | 'cancel' | 'destructive';
    }[],
    options?: { cancelable?: boolean }
  ) => {
    showAlert({
      title,
      message: message || '',
      buttons: buttons || [{ text: '确定', style: 'default' }],
    });
  },
};