Files
SRCmail/hooks/use-confirm-dialog.ts
Matthieu MALVACHEandMatthieu MALVACHE a43096485b feat: add UI/UX polish with navigation rail, confirm dialogs, welcome banner, and form validation
- Add NavigationRail component (desktop vertical icon sidebar + mobile bottom tab bar)
- Add ConfirmDialog with promise-based useConfirmDialog hook for async confirmation flow
- Add WelcomeBanner onboarding component (one-time display, localStorage persistence)
- Polish login form UX (shake on error, TOTP slide animation, password visibility toggle, session expired banner)
- Add inline form validation with shake animation in email composer and contacts
- Add empty state patterns for contacts (no data vs no search results with contextual actions)
- Improve toast notification system with undo action support and typed durations
- Add WCAG AA prefers-reduced-motion media query, safe area insets, sr-only live regions
- Add template settings tab and keyboard shortcut integration
- Update all 8 locale translations
2026-02-17 02:31:50 +01:00

85 lines
1.9 KiB
TypeScript

import { useState, useCallback, useRef, useEffect } from "react";
interface ConfirmDialogState {
isOpen: boolean;
title: string;
message: string;
confirmText?: string;
cancelText?: string;
variant: "default" | "destructive";
onConfirm: () => void;
}
const INITIAL_STATE: ConfirmDialogState = {
isOpen: false,
title: "",
message: "",
variant: "default",
onConfirm: () => {},
};
interface ConfirmOptions {
title: string;
message: string;
confirmText?: string;
cancelText?: string;
variant?: "default" | "destructive";
}
export function useConfirmDialog() {
const [state, setState] = useState<ConfirmDialogState>(INITIAL_STATE);
const resolveRef = useRef<((value: boolean) => void) | null>(null);
useEffect(() => {
return () => {
if (resolveRef.current) {
resolveRef.current(false);
resolveRef.current = null;
}
};
}, []);
const confirm = useCallback(
(options: ConfirmOptions): Promise<boolean> => {
return new Promise((resolve) => {
resolveRef.current = resolve;
setState({
isOpen: true,
title: options.title,
message: options.message,
confirmText: options.confirmText,
cancelText: options.cancelText,
variant: options.variant || "default",
onConfirm: () => {
resolveRef.current = null;
resolve(true);
},
});
});
},
[]
);
const close = useCallback(() => {
if (resolveRef.current) {
resolveRef.current(false);
resolveRef.current = null;
}
setState(INITIAL_STATE);
}, []);
return {
dialogProps: {
isOpen: state.isOpen,
onClose: close,
onConfirm: state.onConfirm,
title: state.title,
message: state.message,
confirmText: state.confirmText,
cancelText: state.cancelText,
variant: state.variant,
},
confirm,
};
}