feat: response in mobile and accouting

This commit is contained in:
2026-08-17 07:44:00 +03:30
parent e3071b8692
commit 90a66031bd
20 changed files with 556 additions and 114 deletions
+100
View File
@@ -0,0 +1,100 @@
'use client';
import { useEffect } from 'react';
import { ExclamationTriangleIcon } from '@heroicons/react/24/outline';
interface ConfirmDialogProps {
open: boolean;
title: string;
message: string;
confirmLabel?: string;
cancelLabel?: string;
tone?: 'danger' | 'primary';
isLoading?: boolean;
onConfirm: () => void;
onCancel: () => void;
}
// Styled replacement for the native confirm() dialog so destructive actions
// match the rest of the panel.
export default function ConfirmDialog({
open,
title,
message,
confirmLabel = 'تأیید',
cancelLabel = 'انصراف',
tone = 'danger',
isLoading = false,
onConfirm,
onCancel,
}: ConfirmDialogProps) {
useEffect(() => {
if (!open) return;
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === 'Escape' && !isLoading) onCancel();
};
document.addEventListener('keydown', handleKeyDown);
return () => document.removeEventListener('keydown', handleKeyDown);
}, [open, isLoading, onCancel]);
if (!open) return null;
const confirmClass =
tone === 'danger'
? 'bg-red-600 hover:bg-red-700 focus:ring-red-500/30 shadow-red-500/20'
: 'bg-indigo-600 hover:bg-indigo-700 focus:ring-indigo-500/30 shadow-indigo-500/20';
const iconWrapClass =
tone === 'danger'
? 'bg-red-50 text-red-600 dark:bg-red-500/10 dark:text-red-400'
: 'bg-indigo-50 text-indigo-600 dark:bg-indigo-500/10 dark:text-indigo-400';
return (
<div
className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 dark:bg-black/60 p-4"
onClick={() => {
if (!isLoading) onCancel();
}}
>
<div
className="bg-white dark:bg-gray-900 rounded-2xl shadow-xl ring-1 ring-gray-200 dark:ring-gray-800 w-full max-w-md"
dir="rtl"
onClick={(event) => event.stopPropagation()}
role="alertdialog"
aria-modal="true"
aria-label={title}
>
<div className="px-6 py-5 flex items-start gap-4">
<div className={`flex-shrink-0 h-11 w-11 rounded-xl flex items-center justify-center ${iconWrapClass}`}>
<ExclamationTriangleIcon className="h-6 w-6" />
</div>
<div className="min-w-0">
<h3 className="text-base font-semibold text-gray-900 dark:text-gray-100">{title}</h3>
<p className="mt-1.5 text-sm text-gray-500 dark:text-gray-400 leading-6">{message}</p>
</div>
</div>
<div className="flex justify-end gap-3 px-6 py-4 border-t border-gray-100 dark:border-gray-800">
<button
type="button"
onClick={onCancel}
disabled={isLoading}
className="px-5 py-2.5 rounded-xl border border-gray-200 dark:border-gray-700 text-sm font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 disabled:opacity-50 transition-colors"
>
{cancelLabel}
</button>
<button
type="button"
onClick={onConfirm}
disabled={isLoading}
className={`inline-flex items-center gap-2 px-5 py-2.5 rounded-xl text-white text-sm font-medium focus:outline-none focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 disabled:opacity-50 transition-colors shadow-sm ${confirmClass}`}
>
{isLoading && (
<span className="h-4 w-4 border-2 border-white/40 border-t-white rounded-full animate-spin" />
)}
{isLoading ? 'در حال انجام...' : confirmLabel}
</button>
</div>
</div>
</div>
);
}
+1 -1
View File
@@ -139,7 +139,7 @@ export default function PersianDatePicker({
</button>
{open && (
<div className="absolute right-0 z-50 mt-2 bg-white dark:bg-gray-900 ring-1 ring-gray-200 dark:ring-gray-800 rounded-2xl shadow-xl p-2">
<div className="absolute right-0 z-50 mt-2 bg-white dark:bg-gray-900 ring-1 ring-gray-200 dark:ring-gray-800 rounded-2xl shadow-xl p-2 max-w-[calc(100vw-3rem)] overflow-x-auto">
<DayPicker
mode="single"
selected={selectedDate ?? undefined}
+1 -1
View File
@@ -34,7 +34,7 @@ export default function StepIndicator({ steps }: StepIndicatorProps) {
)}
</div>
<span
className={`mt-1.5 text-xs font-medium whitespace-nowrap ${
className={`mt-1.5 text-[10px] sm:text-xs font-medium whitespace-nowrap ${
step.isCurrent
? 'text-indigo-700 dark:text-indigo-400'
: step.isCompleted