ميزة: إضافة مكوني ProcedureSelection و StepProgress لأداة مخططات التدفق بصيغة PDF

- تنفيذ مكون ProcedureSelection لتمكين المستخدمين من اختيار الإجراءات من قائمة، وإدارة الاختيارات، ومعالجة الإجراءات المرفوضة.

- إنشاء مكون StepProgress لعرض تقدم معالج متعدد الخطوات بشكل مرئي.

- تعريف أنواع مشتركة للإجراءات، وخطوات التدفق، ورسائل الدردشة في ملف types.ts.

- إضافة اختبارات وحدة لخطافات useFileUpload و useTaskPolling لضمان الأداء السليم ومعالجة الأخطاء.

- تنفيذ اختبارات واجهة برمجة التطبيقات (API) للتحقق من تنسيقات نقاط النهاية وضمان اتساق ربط الواجهة الأمامية بالخلفية.
This commit is contained in:
Your Name
2026-03-06 17:16:09 +02:00
parent 2e97741d60
commit cfbcc8bd79
62 changed files with 10567 additions and 101 deletions

View File

@@ -1,8 +1,10 @@
import { useState, useCallback } from 'react';
import { useDropzone } from 'react-dropzone';
import { useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { Upload, Sparkles } from 'lucide-react';
import { Upload, Sparkles, PenLine } from 'lucide-react';
import ToolSelectorModal from '@/components/shared/ToolSelectorModal';
import { useFileStore } from '@/stores/fileStore';
import { getToolsForFile, detectFileCategory, getCategoryLabel } from '@/utils/fileRouting';
import type { ToolOption } from '@/utils/fileRouting';
@@ -23,6 +25,8 @@ const ACCEPTED_TYPES = {
export default function HeroUploadZone() {
const { t } = useTranslation();
const navigate = useNavigate();
const setStoreFile = useFileStore((s) => s.setFile);
const [selectedFile, setSelectedFile] = useState<File | null>(null);
const [matchedTools, setMatchedTools] = useState<ToolOption[]>([]);
const [fileTypeLabel, setFileTypeLabel] = useState('');
@@ -102,11 +106,50 @@ export default function HeroUploadZone() {
</div>
{/* CTA Text */}
<p className="mb-1 text-lg font-semibold text-slate-800 dark:text-slate-200">
{t('home.uploadCta')}
</p>
<div className="mb-6 flex gap-3 justify-center z-10 relative">
<button
type="button"
className="px-6 py-3 bg-red-600 hover:bg-red-700 text-white font-bold rounded-xl shadow-md transition-colors"
onClick={(e) => {
e.stopPropagation();
const input = document.createElement('input');
input.type = 'file';
input.accept = Object.values(ACCEPTED_TYPES).flat().join(',');
input.onchange = (ev) => {
const fileInput = ev.target as HTMLInputElement;
const f = fileInput.files?.[0];
if (f) onDrop([f]);
};
input.click();
}}
>
{t('home.uploadCta', 'Choose File')}
</button>
<button
onClick={(e) => {
e.stopPropagation();
const input = document.createElement('input');
input.type = 'file';
input.accept = '.pdf';
input.onchange = (ev) => {
const fileInput = ev.target as HTMLInputElement;
const f = fileInput.files?.[0];
if (f) {
setStoreFile(f);
navigate('/tools/pdf-editor');
}
};
input.click();
}}
className="px-6 py-3 bg-slate-900 hover:bg-slate-800 text-white font-bold rounded-xl shadow-md transition-colors flex items-center gap-2"
>
<PenLine className="h-5 w-5" />
{t('home.editNow')}
</button>
</div>
<p className="mb-3 text-sm text-slate-500 dark:text-slate-400">
{t('home.uploadOr')}
{t('common.dragDrop', 'or drop files here')}
</p>
{/* Supported formats */}

View File

@@ -22,21 +22,21 @@ export default function ToolCard({
bgColor,
}: ToolCardProps) {
return (
<Link to={to} className="tool-card group block">
<div className="flex items-start gap-4">
<div
className={`flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-xl ${bgColor}`}
>
{icon}
</div>
<div className="min-w-0 flex-1">
<h3 className="text-base font-semibold text-slate-900 group-hover:text-primary-600 transition-colors dark:text-slate-100 dark:group-hover:text-primary-400">
<Link to={to} className="group block h-full">
<div className="flex h-full flex-col gap-3 rounded-2xl bg-white p-5 shadow-sm ring-1 ring-slate-200 transition-all duration-200 hover:-translate-y-1 hover:shadow-md hover:ring-primary-300 dark:bg-slate-800 dark:ring-slate-700 dark:hover:ring-primary-500">
<div className="flex items-center gap-4">
<div
className={`flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-xl transition-colors ${bgColor} dark:bg-slate-700 dark:group-hover:bg-slate-600`}
>
{icon}
</div>
<h3 className="text-base font-bold text-slate-900 transition-colors group-hover:text-primary-600 dark:text-slate-100 dark:group-hover:text-primary-400">
{title}
</h3>
<p className="mt-1 text-sm text-slate-500 line-clamp-2 dark:text-slate-400">
{description}
</p>
</div>
<p className="text-sm text-slate-500 line-clamp-2 dark:text-slate-400 mt-1">
{description}
</p>
</div>
</Link>
);