From 561bf9d5d520409eb6d507025f72ff7c0bc16ca0 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Sun, 17 Aug 2025 11:31:29 +0330 Subject: [PATCH] remove comments --- src/App.tsx | 10 +------ src/components/EmailNotifications.tsx | 18 ++----------- src/components/EmojiReaction.tsx | 1 - src/components/Filters.tsx | 15 ++--------- src/components/Input.tsx | 4 +-- src/components/Pagination.tsx | 1 - src/components/RowActionsDropdown.tsx | 5 +--- src/components/SoundSettings.tsx | 6 ----- src/components/Table.tsx | 27 +------------------ src/components/Toast.tsx | 6 +---- src/components/newMessage/EmailInput.tsx | 3 --- .../newMessage/hooks/useNewMessage.ts | 12 --------- src/components/newMessage/hooks/useReply.ts | 5 ---- src/config/func.ts | 27 +++---------------- src/hooks/useEmailActions.tsx | 6 ----- src/hooks/useEmailEvents.ts | 1 - src/hooks/useEmailWebSocket.ts | 2 -- src/hooks/useNumberFont.ts | 2 -- src/pages/Trash/List.tsx | 5 ---- src/pages/Trash/service/TrashService.ts | 3 --- src/pages/search/List.tsx | 5 ---- src/pages/sent/List.tsx | 5 ---- src/pages/sent/service/SentService.ts | 1 - src/pages/spam/service/SpamService.ts | 1 - src/services/EmailActionsService.ts | 13 --------- src/shared/SideBar.tsx | 1 - 26 files changed, 13 insertions(+), 172 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 95da014..1cda332 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -40,7 +40,6 @@ i18next.init({ const queryClient = new QueryClient({ queryCache: new QueryCache({ onError: async (error: IApiErrorRepsonse) => { - // نمایش پیغام خطا از API const errorMessage = error?.response?.error?.message?.[0] || undefined; if (errorMessage) { @@ -49,9 +48,8 @@ const queryClient = new QueryClient({ if (error?.response?.status === 401) { try { - // Use a flag to track if refresh is in progress + if (window.isRefreshingToken) { - // Wait for the refresh to complete await new Promise(resolve => { const checkComplete = setInterval(() => { if (!window.isRefreshingToken) { @@ -63,7 +61,6 @@ const queryClient = new QueryClient({ return; } - // Set the flag to indicate refresh is in progress window.isRefreshingToken = true; try { @@ -71,15 +68,12 @@ const queryClient = new QueryClient({ const { data } = await refreshToken({ refreshToken: refreshTokenValue || '' }); if (data?.accessToken?.token) { - // Save the new token await setToken(data?.accessToken?.token); - // If refresh token also returned, update it if (data.refreshToken?.token) { await setRefreshToken(data.refreshToken?.token); } - // Retry the failed request queryClient.invalidateQueries(); return; } else { @@ -90,7 +84,6 @@ const queryClient = new QueryClient({ } } catch (refreshError: unknown) { console.error('Token refresh failed:', refreshError); - // Clear tokens and redirect to login await removeToken(); await removeRefreshToken(); window.location.href = '/auth/login'; @@ -102,7 +95,6 @@ const queryClient = new QueryClient({ queries: { refetchOnWindowFocus: false, retry: false - // staleTime: 86400000 // 1 day in milliseconds } } }); diff --git a/src/components/EmailNotifications.tsx b/src/components/EmailNotifications.tsx index e70483a..08b7672 100644 --- a/src/components/EmailNotifications.tsx +++ b/src/components/EmailNotifications.tsx @@ -23,11 +23,9 @@ export const EmailNotifications: React.FC = ({ onError: () => null, }); - // Sound settings state const [soundEnabled, setSoundEnabled] = useState(true); const [soundVolume, setSoundVolume] = useState(0.7); - // Load sound settings from localStorage useEffect(() => { const savedEnabled = localStorage.getItem('notificationSoundEnabled'); const savedVolume = localStorage.getItem('notificationSoundVolume'); @@ -40,26 +38,21 @@ export const EmailNotifications: React.FC = ({ } }, []); - // Notification sound hook const { playSound } = useNotificationSound({ enabled: soundEnabled, volume: soundVolume, }); const handleNewEmail = useCallback((email: EmailPayload) => { + setNotifications(prev => [email, ...prev.slice(0, 9)]); - // Add to notifications list - setNotifications(prev => [email, ...prev.slice(0, 9)]); // Keep only 10 latest - - // Show browser notification if permission granted if (Notification.permission === 'granted') { new Notification(`📧 ایمیل جدید: ${email.subject}`, { body: `از: ${email.from.name || email.from.address}\n${email.preview}`, - tag: `email-${email.messageId}`, // Prevent duplicates + tag: `email-${email.messageId}`, }); } - // Play notification sound playSound(); }, [playSound]); @@ -68,14 +61,12 @@ export const EmailNotifications: React.FC = ({ }, []); const handleEmailRead = useCallback((data: { messageId: number }) => { - // Remove from notifications if it was there setNotifications(prev => prev.filter(notification => notification.messageId !== data.messageId) ); }, []); const handleEmailSent = useCallback((data: EmailStatusPayload) => { - // Remove from notifications if it was there setNotifications(prev => prev.filter(notification => notification.messageId !== data.messageId) ); @@ -88,7 +79,6 @@ export const EmailNotifications: React.FC = ({ onEmailSent: handleEmailSent, }); - // Request notification permission on mount React.useEffect(() => { if (Notification.permission === 'default') { Notification.requestPermission(); @@ -97,11 +87,9 @@ export const EmailNotifications: React.FC = ({ return (
- {/* Connection Status */}
- {/* Test Sound Button */} - {/* Notification Bell */}
setIsVisible(!isVisible)} @@ -125,7 +112,6 @@ export const EmailNotifications: React.FC = ({ )}
- {/* Notifications Dropdown */} {isVisible && (
diff --git a/src/components/EmojiReaction.tsx b/src/components/EmojiReaction.tsx index 4503ed2..d17485c 100644 --- a/src/components/EmojiReaction.tsx +++ b/src/components/EmojiReaction.tsx @@ -11,7 +11,6 @@ interface EmojiReactionProps { const EmojiReaction: FC = ({ onEmojiSelect, className = '' }) => { const [isOpen, setIsOpen] = useState(false) - // استفاده از hook موجود برای تشخیص کلیک خارج از المان const containerRef = useOutsideClick(() => { if (isOpen) { setIsOpen(false) diff --git a/src/components/Filters.tsx b/src/components/Filters.tsx index 4909655..f56f4a5 100644 --- a/src/components/Filters.tsx +++ b/src/components/Filters.tsx @@ -7,7 +7,6 @@ import DefaulModal from './DefaulModal'; import moment from 'moment-jalaali' import Button from './Button'; -// تعریف نوع داده برای فیلدهای مختلف export type DateFieldType = { type: 'date'; name: string; @@ -32,7 +31,6 @@ export type InputFieldType = { export type FieldType = DateFieldType | SelectFieldType | InputFieldType; -// تعریف نوع داده برای مقادیر فیلترها export type FilterValues = Record; interface FiltersProps { @@ -41,7 +39,7 @@ interface FiltersProps { initialValues?: FilterValues; className?: string; fieldClassName?: string; - searchField?: string; // نام فیلد جستجو که باید در انتها نمایش داده شود + searchField?: string; } const Filters: FC = ({ @@ -50,23 +48,20 @@ const Filters: FC = ({ initialValues = {}, className = "mt-6 md:mt-8 xl:mt-10 flex flex-col md:flex-row justify-between items-start md:items-center gap-4", fieldClassName = "flex flex-col sm:flex-row gap-3 md:gap-4 w-full md:w-auto", - searchField = "search" // پیش‌فرض فیلد سرچ با نام search + searchField = "search" }) => { const [filters, setFilters] = useState({}); const [isFiltersOpen, setIsFiltersOpen] = useState(false); const [inputValues, setInputValues] = useState>({}); const onChangeRef = useRef(onChange); - // آپدیت کردن ref وقتی onChange تغییر می‌کند useEffect(() => { onChangeRef.current = onChange; }, [onChange]); - // تنظیم مقادیر اولیه useEffect(() => { if (Object.keys(initialValues).length > 0) { setFilters(initialValues); - // تنظیم مقادیر input برای فیلدهای نوع input const inputFields: Record = {}; fields.forEach(field => { if (field.type === 'input' && initialValues[field.name]) { @@ -75,7 +70,6 @@ const Filters: FC = ({ }); setInputValues(inputFields); } else { - // تنظیم مقادیر پیش‌فرض از فیلدها const defaultValues: FilterValues = {}; const defaultInputs: Record = {}; fields.forEach(field => { @@ -95,7 +89,6 @@ const Filters: FC = ({ } }, [fields, initialValues, onChange]); - // Debounce برای فیلدهای input useEffect(() => { const timeouts: Record = {}; @@ -170,13 +163,11 @@ const Filters: FC = ({ } }; - // جداسازی فیلد جستجو از سایر فیلدها const searchFieldObj = fields.find(field => field.name === searchField); const otherFields = fields.filter(field => field.name !== searchField); return (
- {/* آیکون فیلتر برای موبایل */}
- {/* فیلترها برای دسکتاپ (همیشه نمایش داده می‌شوند) */}
{otherFields.map(renderField)} @@ -204,7 +194,6 @@ const Filters: FC = ({ )}
- {/* فیلترها برای موبایل (در قالب مودال) */} setIsFiltersOpen(false)} diff --git a/src/components/Input.tsx b/src/components/Input.tsx index de90b15..6ef0b9d 100644 --- a/src/components/Input.tsx +++ b/src/components/Input.tsx @@ -42,13 +42,11 @@ const Input: FC = (props: Props) => { const handleInputChange = (event: React.ChangeEvent) => { if (props.seprator) { - const inputValue = event.target.value.replace(/,/g, ''); // حذف کاماها + const inputValue = event.target.value.replace(/,/g, ''); const formatted = formatNumber(inputValue); - // به‌روزرسانی مقدار قالب‌بندی‌شده setFormattedValue(formatted); - // ارسال مقدار خام به `onChange` والد props.onChange?.({ ...event, target: { diff --git a/src/components/Pagination.tsx b/src/components/Pagination.tsx index 904f8b7..d2a39d8 100644 --- a/src/components/Pagination.tsx +++ b/src/components/Pagination.tsx @@ -16,7 +16,6 @@ const Pagination: React.FC = ({ onNext, onPrevious, }) => { - // اگر hasNext فالس باشد، pagination نمایش داده نمی‌شود if (!hasNext && !previousCursor) return null; return ( diff --git a/src/components/RowActionsDropdown.tsx b/src/components/RowActionsDropdown.tsx index 5b6f5ff..3374da4 100644 --- a/src/components/RowActionsDropdown.tsx +++ b/src/components/RowActionsDropdown.tsx @@ -40,22 +40,19 @@ const RowActionsDropdown: React.FC = ({ actions, classN const rect = buttonRef.current.getBoundingClientRect(); const isMobile = window.innerWidth < 768; const dropdownWidth = isMobile ? 140 : 150; - const dropdownHeight = actions.length * (isMobile ? 36 : 40); // تخمین ارتفاع منو + const dropdownHeight = actions.length * (isMobile ? 36 : 40); let left = rect.left + window.scrollX - dropdownWidth + rect.width; let top = rect.bottom + window.scrollY; - // بررسی اینکه منو از سمت راست خارج نشود if (left + dropdownWidth > window.innerWidth) { left = rect.left + window.scrollX - dropdownWidth; } - // بررسی اینکه منو از سمت چپ خارج نشود if (left < 0) { left = isMobile ? 20 : 40; } - // بررسی اینکه منو از پایین خارج نشود if (top + dropdownHeight > window.innerHeight + window.scrollY) { top = rect.top + window.scrollY - dropdownHeight; } diff --git a/src/components/SoundSettings.tsx b/src/components/SoundSettings.tsx index 543aaa9..56d6faf 100644 --- a/src/components/SoundSettings.tsx +++ b/src/components/SoundSettings.tsx @@ -15,7 +15,6 @@ export const SoundSettings: React.FC = ({ className = '' }) volume: volume, }); - // Load settings from localStorage on mount useEffect(() => { const savedEnabled = localStorage.getItem('notificationSoundEnabled'); const savedVolume = localStorage.getItem('notificationSoundVolume'); @@ -28,7 +27,6 @@ export const SoundSettings: React.FC = ({ className = '' }) } }, []); - // Save settings to localStorage when changed useEffect(() => { localStorage.setItem('notificationSoundEnabled', isEnabled.toString()); localStorage.setItem('notificationSoundVolume', volume.toString()); @@ -37,7 +35,6 @@ export const SoundSettings: React.FC = ({ className = '' }) const handleVolumeChange = (newVolume: number) => { setVolume(newVolume); if (isEnabled) { - // Test sound with new volume setTimeout(() => playSound(), 100); } }; @@ -46,7 +43,6 @@ export const SoundSettings: React.FC = ({ className = '' }) const newEnabled = !isEnabled; setIsEnabled(newEnabled); if (newEnabled) { - // Test sound when enabling setTimeout(() => playSound(), 100); } }; @@ -59,7 +55,6 @@ export const SoundSettings: React.FC = ({ className = '' }) return (
- {/* Sound Toggle */} - {/* Volume Slider */} {isEnabled && (
({ const longPressTimer = useRef(null); const [longPressActiveId, setLongPressActiveId] = useState(null); - // استفاده از selectedRows خارجی اگر موجود باشد، در غیر این صورت از internal استفاده کن const selectedRows = externalSelectedRows !== undefined ? externalSelectedRows : internalSelectedRows; - // پاک کردن انتخاب‌ها وقتی clearSelection تغییر کند React.useEffect(() => { if (clearSelection && externalSelectedRows === undefined) { setInternalSelectedRows([]); } - // خروج از حالت انتخاب موبایل هم if (clearSelection) { setMobileSelectionMode(false); } }, [clearSelection, externalSelectedRows]); - // تمیز کردن timer هنگام unmount React.useEffect(() => { return () => { if (longPressTimer.current) { @@ -58,7 +54,6 @@ const Table = ({ }; }, []); - // خروج از حالت انتخاب اگر هیچ آیتمی انتخاب نشده، ورود اگر آیتمی انتخاب شده React.useEffect(() => { if (selectedRows.length === 0 && mobileSelectionMode) { setMobileSelectionMode(false); @@ -73,10 +68,9 @@ const Table = ({ setLongPressActiveId(item.id); longPressTimer.current = window.setTimeout(() => { setMobileSelectionMode(true); - // انتخاب آیتم فعلی handleSingleRowSelect(item, true); setLongPressActiveId(null); - }, 500); // 500ms برای long press + }, 500); }; const handleLongPressEnd = () => { @@ -89,11 +83,9 @@ const Table = ({ const handleMobileRowClick = (item: T) => { if (mobileSelectionMode) { - // در حالت انتخاب، آیتم را انتخاب/عدم انتخاب کن const isSelected = isRowSelected(item); handleSingleRowSelect(item, !isSelected); } else if (longPressActiveId !== item.id) { - // در حالت عادی، row click عادی را اجرا کن handleRowClick(item); } }; @@ -120,12 +112,10 @@ const Table = ({ const newSelectedRows = selectedRows.length === data.length ? [] : [...data]; if (externalSelectedRows !== undefined) { - // اگر selectedRows از خارج کنترل می‌شود، فقط callback را فراخوانی کن if (onSelectionChange) { onSelectionChange(newSelectedRows); } } else { - // در غیر این صورت internal state را به‌روزرسانی کن setInternalSelectedRows(newSelectedRows); if (onSelectionChange) { onSelectionChange(newSelectedRows); @@ -139,12 +129,10 @@ const Table = ({ : selectedRows.filter((row) => row.id !== item.id); if (externalSelectedRows !== undefined) { - // اگر selectedRows از خارج کنترل می‌شود، فقط callback را فراخوانی کن if (onSelectionChange) { onSelectionChange(newSelectedRows); } } else { - // در غیر این صورت internal state را به‌روزرسانی کن setInternalSelectedRows(newSelectedRows); if (onSelectionChange) { onSelectionChange(newSelectedRows); @@ -156,7 +144,6 @@ const Table = ({ return selectedRows.some((row) => row.id === item.id); }; - // Gmail-style layout برای وقتی header نمایش داده نمی‌شود const renderGmailStyleRows = () => { const hasActions = (actionsPosition === 'top' || actionsPosition === 'above-header') && (actions || (selectable && selectedRows.length > 0 && selectedActions)); const roundedClass = hasActions ? 'rounded-b-2xl' : 'rounded-2xl'; @@ -183,7 +170,6 @@ const Table = ({ return (
{data.map((item, rowIndex) => { - // Gmail-style: خوانده نشده = پس‌زمینه سفید، خوانده شده = پس‌زمینه خاکستری const isUnread = 'seen' in item && !item.seen; const bgColor = isUnread ? 'bg-white' : 'bg-gray-50'; const hoverColor = isUnread ? 'hover:bg-gray-50' : 'hover:bg-gray-100'; @@ -213,16 +199,11 @@ const Table = ({
)} - {/* Inline Actions - بعد از checkbox */} - -
- {/* محتوای اصلی - ستون اول */}
{columns[0]?.render ? columns[0].render(item) : (item[columns[0]?.key] as React.ReactNode)}
- {/* اطلاعات اضافی - سه ستون آخر در یک خط */} {columns.length > 1 && (
{columns.slice(1).map((col) => ( @@ -269,7 +250,6 @@ const Table = ({ ); } return data.map((item, rowIndex) => { - // Gmail-style: خوانده نشده = پس‌زمینه سفید، خوانده شده = پس‌زمینه خاکستری const isUnread = 'seen' in item && !item.seen; const bgColor = isUnread ? 'bg-white' : 'bg-gray-50'; const hoverColor = isUnread ? 'hover:bg-gray-50' : 'hover:bg-gray-100'; @@ -378,11 +358,9 @@ const Table = ({ ); }; - // اگر header نشان داده نمی‌شود، از Gmail-style layout فقط در موبایل استفاده کن if (!showHeader) { return (
- {/* نسخه موبایل - Gmail style */}
{(actionsPosition === 'top' || actionsPosition === 'above-header') && (
@@ -394,7 +372,6 @@ const Table = ({
- {/* نسخه دسکتاپ - Table معمولی */}
{(actionsPosition === 'top' || actionsPosition === 'above-header') && (
@@ -509,7 +485,6 @@ const MyComponent = () => { const handlePageChange = (page: number) => { setCurrentPage(page); - // اینجا می‌توانید API call جدید برای دریافت داده‌های صفحه جدید بزنید }; return ( diff --git a/src/components/Toast.tsx b/src/components/Toast.tsx index 6bce2a4..85e4caf 100644 --- a/src/components/Toast.tsx +++ b/src/components/Toast.tsx @@ -13,24 +13,20 @@ let addToast: (toast: Toast) => void; const ToastContainer: React.FC = () => { const [toasts, setToasts] = useState([]); - // ثبت toast جدید const showToast = (toast: Toast) => { setToasts((prev) => [...prev, toast]); - // حذف خودکار بعد از ۳ ثانیه setTimeout(() => { setToasts((prev) => prev.map(t => t.id === toast.id ? { ...t, isExiting: true } : t )); - // حذف از DOM بعد از اتمام انیمیشن setTimeout(() => { setToasts((prev) => prev.filter((t) => t.id !== toast.id)); - }, 300); // مدت زمان انیمیشن خروج + }, 300); }, 3000); }; - // تخصیص تابع نمایش toast به متغیر سراسری useEffect(() => { addToast = showToast; }, []); diff --git a/src/components/newMessage/EmailInput.tsx b/src/components/newMessage/EmailInput.tsx index 440aee0..c41fe02 100644 --- a/src/components/newMessage/EmailInput.tsx +++ b/src/components/newMessage/EmailInput.tsx @@ -38,7 +38,6 @@ const EmailInput: FC = ({ return } - // Always search via API for fresh results if (onSearchSuggestions) { if (searchTimeoutRef.current) { clearTimeout(searchTimeoutRef.current) @@ -51,7 +50,6 @@ const EmailInput: FC = ({ setSelectedSuggestionIndex(-1) } - // Update filtered suggestions when API suggestions change useEffect(() => { if (suggestions.length > 0) { const filtered = suggestions @@ -63,7 +61,6 @@ const EmailInput: FC = ({ setFilteredSuggestions(filtered) setShowSuggestions(filtered.length > 0 && to.trim().length > 0) } else if (to.trim() === '') { - // Clear suggestions when input is empty setFilteredSuggestions([]) setShowSuggestions(false) } diff --git a/src/components/newMessage/hooks/useNewMessage.ts b/src/components/newMessage/hooks/useNewMessage.ts index f6cff9b..2c6e0c6 100644 --- a/src/components/newMessage/hooks/useNewMessage.ts +++ b/src/components/newMessage/hooks/useNewMessage.ts @@ -20,35 +20,29 @@ export const useNewMessage = () => { } = useSharedStore(); const { email: userEmail } = useAuthStore(); - // Form state const [toEmails, setToEmails] = useState([]); const [subject, setSubject] = useState(""); const [content, setContent] = useState(""); const [priority, setPriority] = useState(""); const [attachments, setAttachments] = useState([]); - // Loading states const [isSending, setIsSending] = useState(false); const [isSavingDraft, setIsSavingDraft] = useState(false); - // API hooks const sendEmailMutation = useSendEmail(); const updateDraftMutation = useUpdateDraft(); const sendDraftMutation = useSendDraft(); - // Email suggestions const { suggestions: emailSuggestions, searchSuggestions, } = useEmailSuggestions(); - // Get draft detail if draftData exists const { data: draftDetail } = useGetMessageDetail( draftData?.id.toString() || "", draftData?.mailbox || "" ); - // Load draft data into form useEffect(() => { if (draftDetail) { const toEmailsList = @@ -81,7 +75,6 @@ export const useNewMessage = () => { return emailRegex.test(email); }; - // Function to search email suggestions const searchEmailSuggestions = (query: string) => { searchSuggestions(query); }; @@ -237,7 +230,6 @@ export const useNewMessage = () => { }; return { - // Form state toEmails, subject, content, @@ -245,11 +237,9 @@ export const useNewMessage = () => { attachments, emailSuggestions, - // Loading states isSending, isSavingDraft, - // Form handlers addEmail, removeEmail, setSubject, @@ -257,10 +247,8 @@ export const useNewMessage = () => { setPriority, setAttachments, - // Search functions searchEmailSuggestions, - // Actions handleSend, handleSaveDraft, resetForm, diff --git a/src/components/newMessage/hooks/useReply.ts b/src/components/newMessage/hooks/useReply.ts index a25db4b..8ddff45 100644 --- a/src/components/newMessage/hooks/useReply.ts +++ b/src/components/newMessage/hooks/useReply.ts @@ -20,7 +20,6 @@ export const useReply = ({ const [content, setContent] = useState(""); const [isExpanded, setIsExpanded] = useState(false); - // API hooks const sendEmailMutation = useSendEmail(); const resetForm = () => { @@ -39,7 +38,6 @@ export const useReply = ({ return false; } - // Format date to Persian const originalDate = new Date(originalMessage.date); const persianDate = new Intl.DateTimeFormat("fa-IR", { weekday: "long", @@ -143,12 +141,10 @@ ${ }; return { - // State content, isExpanded, isSending: sendEmailMutation.isPending, - // Handlers setContent, expandReply, collapseReply, @@ -156,7 +152,6 @@ ${ handleSaveDraft, resetForm, - // Original message data originalMessage, }; }; diff --git a/src/config/func.ts b/src/config/func.ts index cf04bc5..5327686 100644 --- a/src/config/func.ts +++ b/src/config/func.ts @@ -41,7 +41,7 @@ export const removeRefreshToken = async () => { export const timeAgo = (date: string | Date): string => { const now = new Date(); const past = new Date(date); - const diff = Math.floor((now.getTime() - past.getTime()) / 1000); // اختلاف بر حسب ثانیه + const diff = Math.floor((now.getTime() - past.getTime()) / 1000); const units = [ { name: "سال", value: 60 * 60 * 24 * 365 }, @@ -82,48 +82,33 @@ export const formatDate = (dateString: string) => { }; export const detectTextDirection = (text: string): "ltr" | "rtl" => { - // حذف تگ‌های HTML برای تحلیل فقط متن const plainText = text.replace(/<[^>]*>/g, " ").trim(); - // اگر متن خالی است، از RTL استفاده کن if (!plainText) return "rtl"; - // الگوی کاراکترهای انگلیسی و اعداد const englishPattern = /[a-zA-Z0-9\s.,!?;:'"()\-@#$%^&*+=<>{}[\]\\|`~_]/g; const englishMatches = plainText.match(englishPattern) || []; - // الگوی کاراکترهای فارسی و عربی (برای آینده ممکن است نیاز باشد) - // const persianArabicPattern = /[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]/g; - - // محاسبه درصد کاراکترهای انگلیسی const totalChars = plainText.replace(/\s/g, "").length; const englishChars = englishMatches.join("").replace(/\s/g, "").length; const englishPercentage = totalChars > 0 ? (englishChars / totalChars) * 100 : 0; - // اگر بیش از 70% متن انگلیسی است، LTR استفاده کن return englishPercentage > 70 ? "ltr" : "rtl"; }; export const sanitizeEmailHTML = (html: string): string => { try { - // Remove style tags and their content let sanitized = html.replace(/]*>[\s\S]*?<\/style>/gi, ""); - // Remove link tags (CSS files) sanitized = sanitized.replace(/]*>/gi, ""); - // Remove script tags for security sanitized = sanitized.replace(/]*>[\s\S]*?<\/script>/gi, ""); - // Remove potentially harmful attributes sanitized = sanitized.replace(/\s*on\w+\s*=\s*["'][^"']*["']/gi, ""); - // تشخیص جهت متن اصلی const detectedDirection = detectTextDirection(sanitized); - // فقط font-family، font-size و font-weight رو از inline styles حذف کن - // text-align و direction رو فقط اگر با جهت تشخیص داده شده مطابقت نداشته باشد حذف کن sanitized = sanitized.replace( /style\s*=\s*["']([^"']*?)["']/gi, (_, styles) => { @@ -132,19 +117,17 @@ export const sanitizeEmailHTML = (html: string): string => { .replace(/font-size\s*:\s*[^;]*;?/gi, "") .replace(/font-weight\s*:\s*[^;]*;?/gi, ""); - // اگر جهت تشخیص داده شده LTR است، direction و text-align را حفظ کن if (detectedDirection === "ltr") { - // direction و text-align را حفظ کن + // TODO: Implement LTR } else { - // اگر RTL است، این استایل‌ها را حذف کن تا استایل سایت اعمال شود cleanedStyles = cleanedStyles .replace(/text-align\s*:\s*[^;]*;?/gi, "") .replace(/direction\s*:\s*[^;]*;?/gi, ""); } cleanedStyles = cleanedStyles - .replace(/;\s*;/g, ";") // حذف سمیکالن‌های اضافی - .replace(/^\s*;\s*|\s*;\s*$/g, ""); // حذف سمیکالن‌های ابتدا و انتها + .replace(/;\s*;/g, ";") + .replace(/^\s*;\s*|\s*;\s*$/g, ""); return cleanedStyles ? `style="${cleanedStyles}"` : ""; } @@ -157,7 +140,6 @@ export const sanitizeEmailHTML = (html: string): string => { } }; -// Interface برای mailbox structure interface MailboxItem { id: string; name: string; @@ -165,7 +147,6 @@ interface MailboxItem { total: number; } -// Utility function برای گرفتن mailbox id از localStorage export const getMailboxId = (mailboxName: string): string | null => { try { const mailboxesStr = localStorage.getItem("mailboxes"); diff --git a/src/hooks/useEmailActions.tsx b/src/hooks/useEmailActions.tsx index 15e302b..9b96b96 100644 --- a/src/hooks/useEmailActions.tsx +++ b/src/hooks/useEmailActions.tsx @@ -20,9 +20,7 @@ import { toast } from '../components/Toast'; export const useEmailActions = (customRefetch?: () => void) => { const queryClient = useQueryClient(); - // تمام query key های موجود در سیستم const invalidateAllQueries = () => { - // صفحه‌های اصلی queryClient.invalidateQueries({ queryKey: ['inbox'] }); queryClient.invalidateQueries({ queryKey: ['drafts'] }); queryClient.invalidateQueries({ queryKey: ['archive-messages'] }); @@ -31,11 +29,9 @@ export const useEmailActions = (customRefetch?: () => void) => { queryClient.invalidateQueries({ queryKey: ['trash-messages'] }); queryClient.invalidateQueries({ queryKey: ['search-messages'] }); - // پیام‌های تکی queryClient.invalidateQueries({ queryKey: ['message'] }); queryClient.invalidateQueries({ queryKey: ['draft'] }); - // صفحه‌هایی که از React Query استفاده نمی‌کنند (مثل sent) if (customRefetch) { customRefetch(); } @@ -162,7 +158,6 @@ export const useEmailActions = (customRefetch?: () => void) => { restoreMutation.isPending; return { - // Bulk actions bulkAction: bulkActionMutation.mutate, bulkMarkAsSeen: (messageIds: number[], mailbox: string) => bulkActionMutation.mutate({ messageIds, action: BulkActionType.SEEN, mailbox: mailbox }), @@ -183,7 +178,6 @@ export const useEmailActions = (customRefetch?: () => void) => { bulkRestore: (messageIds: number[], mailbox: string) => bulkActionMutation.mutate({ messageIds, action: BulkActionType.RESTORE, mailbox: mailbox }), - // Single actions (keeping for backward compatibility) markAsSeen: markAsSeenMutation.mutate, archive: archiveMutation.mutate, favorite: favoriteMutation.mutate, diff --git a/src/hooks/useEmailEvents.ts b/src/hooks/useEmailEvents.ts index 305f19c..9c5cb53 100644 --- a/src/hooks/useEmailEvents.ts +++ b/src/hooks/useEmailEvents.ts @@ -54,7 +54,6 @@ export const useEmailEvents = ( useEffect(() => { if (!socket) return; - // Register event handlers if (handlers.onNewEmail) { socket.on("new_email", handlers.onNewEmail); } diff --git a/src/hooks/useEmailWebSocket.ts b/src/hooks/useEmailWebSocket.ts index eb6c685..f130ff5 100644 --- a/src/hooks/useEmailWebSocket.ts +++ b/src/hooks/useEmailWebSocket.ts @@ -26,7 +26,6 @@ export const useEmailWebSocket = ({ transports: ["websocket", "polling"], }); - // Connection events newSocket.on("connect", () => { setIsConnected(true); onConnect?.(); @@ -43,7 +42,6 @@ export const useEmailWebSocket = ({ onError?.(error.error); }); - // Health monitoring newSocket.on("ping", () => { newSocket.emit("pong", { timestamp: new Date().toISOString() }); }); diff --git a/src/hooks/useNumberFont.ts b/src/hooks/useNumberFont.ts index 5d973f9..7785ca5 100644 --- a/src/hooks/useNumberFont.ts +++ b/src/hooks/useNumberFont.ts @@ -8,11 +8,9 @@ const useDetectLatinAndNumbers = () => { if (node.nodeType === Node.TEXT_NODE) { const textContent = node.nodeValue; if (textContent) { - // اگر عدد داشت if (/\d/.test(textContent)) { element.classList.add("has-number"); } - // اگر حرف لاتین داشت if (/[a-zA-Z]/.test(textContent)) { element.classList.add("has-latin"); } diff --git a/src/pages/Trash/List.tsx b/src/pages/Trash/List.tsx index 1c5f4e9..99eb680 100644 --- a/src/pages/Trash/List.tsx +++ b/src/pages/Trash/List.tsx @@ -32,7 +32,6 @@ const List: FC = () => { const [selectedMessages, setSelectedMessages] = useState([]); const [selectAll, setSelectAll] = useState(false); - // تابع برای گرفتن فقط ساعت const formatTime = (dateString: string) => { try { if (!dateString) return '--:--'; @@ -49,7 +48,6 @@ const List: FC = () => { } }; - // ستون‌های دسکتاپ const desktopColumns: ColumnType[] = [ { key: 'subject', @@ -78,7 +76,6 @@ const List: FC = () => { }, ]; - // ستون‌های موبایل (سه خطی) const mobileColumns: ColumnType[] = [ { key: 'content', @@ -106,7 +103,6 @@ const List: FC = () => { } ]; - // انتخاب ستون‌ها بر اساس سایز صفحه const [isMobile, setIsMobile] = useState(window.innerWidth < 768); React.useEffect(() => { @@ -170,7 +166,6 @@ const List: FC = () => { const handleSelectionChange = (selectedRows: TrashMessage[]) => { setSelectedMessages(selectedRows); - // تنظیم وضعیت select all بر اساس انتخاب شده‌ها const messages = trashData?.data?.trashMails || []; setSelectAll(selectedRows.length === messages.length && messages.length > 0); }; diff --git a/src/pages/Trash/service/TrashService.ts b/src/pages/Trash/service/TrashService.ts index 35af6cc..be9efe5 100644 --- a/src/pages/Trash/service/TrashService.ts +++ b/src/pages/Trash/service/TrashService.ts @@ -10,7 +10,6 @@ export const getTrashMessages = async ( !!query.search || !!query.datestart || query.dateend || query.from; const url = isSearch ? "search" : "messages/trash"; - // اضافه کردن mailbox id از localStorage const mailboxId = getMailboxId("Trash"); const queryWithMailbox = { ...query, @@ -23,8 +22,6 @@ export const getTrashMessages = async ( return data; }; -// Note: deleteMessagePermanently and restoreMessage are now handled by EmailActionsService - export const emptyTrash = async () => { const mailboxId = getMailboxId(MailboxEnum.TRASH); const { data } = await axios.patch( diff --git a/src/pages/search/List.tsx b/src/pages/search/List.tsx index 7c9fe60..192ccf8 100644 --- a/src/pages/search/List.tsx +++ b/src/pages/search/List.tsx @@ -28,7 +28,6 @@ const List: FC = () => { const [selectedMessages, setSelectedMessages] = useState([]); const [selectAll, setSelectAll] = useState(false); - // تابع برای گرفتن فقط ساعت const formatTime = (dateString: string) => { try { if (!dateString) return '--:--'; @@ -45,7 +44,6 @@ const List: FC = () => { } }; - // ستون‌های دسکتاپ const desktopColumns: ColumnType[] = [ { key: 'subject', @@ -81,7 +79,6 @@ const List: FC = () => { }, ]; - // ستون‌های موبایل (سه خطی) const mobileColumns: ColumnType[] = [ { key: 'content', @@ -112,7 +109,6 @@ const List: FC = () => { } ]; - // انتخاب ستون‌ها بر اساس سایز صفحه const [isMobile, setIsMobile] = useState(window.innerWidth < 768); React.useEffect(() => { @@ -171,7 +167,6 @@ const List: FC = () => { const handleSelectionChange = (selectedRows: SearchMessage[]) => { setSelectedMessages(selectedRows); - // تنظیم وضعیت select all بر اساس انتخاب شده‌ها const messages = searchData?.data?.results || []; setSelectAll(selectedRows.length === messages.length && messages.length > 0); }; diff --git a/src/pages/sent/List.tsx b/src/pages/sent/List.tsx index 1c3600f..6a2c022 100644 --- a/src/pages/sent/List.tsx +++ b/src/pages/sent/List.tsx @@ -29,7 +29,6 @@ const List: FC = () => { const [selectedMessages, setSelectedMessages] = useState([]); const [selectAll, setSelectAll] = useState(false); - // تابع برای گرفتن فقط ساعت const formatTime = (dateString: string) => { try { if (!dateString) return '--:--'; @@ -46,7 +45,6 @@ const List: FC = () => { } }; - // ستون‌های دسکتاپ const desktopColumns: ColumnType[] = [ { key: 'subject', @@ -89,7 +87,6 @@ const List: FC = () => { }, ]; - // ستون‌های موبایل (سه خطی) const mobileColumns: ColumnType[] = [ { key: 'content', @@ -117,7 +114,6 @@ const List: FC = () => { } ]; - // انتخاب ستون‌ها بر اساس سایز صفحه const [isMobile, setIsMobile] = useState(window.innerWidth < 768); React.useEffect(() => { @@ -179,7 +175,6 @@ const List: FC = () => { const handleSelectionChange = (selectedRows: InboxMessage[]) => { setSelectedMessages(selectedRows); - // تنظیم وضعیت select all بر اساس انتخاب شده‌ها const messages = sentData?.data?.sentMails || []; setSelectAll(selectedRows.length === messages.length && messages.length > 0); }; diff --git a/src/pages/sent/service/SentService.ts b/src/pages/sent/service/SentService.ts index 88b4d79..06744bf 100644 --- a/src/pages/sent/service/SentService.ts +++ b/src/pages/sent/service/SentService.ts @@ -14,7 +14,6 @@ export const getSentMessages = async ( !!query.search || !!query.datestart || query.dateend || query.from; const url = isSearch ? "search" : "messages/sent"; - // اضافه کردن mailbox id از localStorage const mailboxId = getMailboxId("Sent Mail"); const queryWithMailbox = { ...query, diff --git a/src/pages/spam/service/SpamService.ts b/src/pages/spam/service/SpamService.ts index 0a9881a..14e9de9 100644 --- a/src/pages/spam/service/SpamService.ts +++ b/src/pages/spam/service/SpamService.ts @@ -10,7 +10,6 @@ export const getSpamMessages = async ( !!query.search || !!query.datestart || query.dateend || query.from; const url = isSearch ? "search" : "messages/junk"; - // اضافه کردن mailbox id از localStorage const mailboxId = getMailboxId("Junk"); const queryWithMailbox = { ...query, diff --git a/src/services/EmailActionsService.ts b/src/services/EmailActionsService.ts index 227d5bc..8b85985 100644 --- a/src/services/EmailActionsService.ts +++ b/src/services/EmailActionsService.ts @@ -1,7 +1,6 @@ import axios from "../config/axios"; import { BulkActionRequest } from "../pages/received/types/Types"; -// Bulk action for multiple messages export const bulkAction = async (request: BulkActionRequest) => { const { data } = await axios.post( `/email/messages/bulk-action?mailbox=${request.mailbox}`, @@ -10,7 +9,6 @@ export const bulkAction = async (request: BulkActionRequest) => { return data; }; -// Mark message as seen export const markMessageAsSeen = async (messageId: number, mailbox: string) => { const { data } = await axios.patch( `/email/messages/${messageId}/seen?mailbox=${mailbox}` @@ -18,7 +16,6 @@ export const markMessageAsSeen = async (messageId: number, mailbox: string) => { return data; }; -// Move message to archive export const moveMessageToArchive = async ( messageId: number, mailbox: string @@ -29,7 +26,6 @@ export const moveMessageToArchive = async ( return data; }; -// Move message to favorite export const moveMessageToFavorite = async ( messageId: number, mailbox: string @@ -40,7 +36,6 @@ export const moveMessageToFavorite = async ( return data; }; -// Move message to trash export const moveMessageToTrash = async ( messageId: number, mailbox: string @@ -51,7 +46,6 @@ export const moveMessageToTrash = async ( return data; }; -// Delete message permanently (only for trash mailbox) export const deleteMessagePermanently = async ( messageId: number, mailbox: string @@ -62,13 +56,11 @@ export const deleteMessagePermanently = async ( return data; }; -// Send email export const sendEmail = async (messageId: number) => { const { data } = await axios.post(`/email/send?messageId=${messageId}`); return data; }; -// Update draft export const updateDraft = async (messageId: number, draftData: unknown) => { const { data } = await axios.patch( `/email/messages/drafts/${messageId}`, @@ -77,7 +69,6 @@ export const updateDraft = async (messageId: number, draftData: unknown) => { return data; }; -// Delete draft export const deleteDraft = async (messageId: number, mailbox: string) => { const { data } = await axios.delete( `/email/messages/drafts/${messageId}?mailbox=${mailbox}` @@ -85,13 +76,11 @@ export const deleteDraft = async (messageId: number, mailbox: string) => { return data; }; -// Send draft export const sendDraft = async (messageId: number) => { const { data } = await axios.post(`/email/messages/drafts/${messageId}/send`); return data; }; -// Unfavorite message export const unfavoriteMessage = async (messageId: number, mailbox: string) => { const { data } = await axios.patch( `/email/messages/${messageId}/unfavorite?mailbox=${mailbox}` @@ -99,7 +88,6 @@ export const unfavoriteMessage = async (messageId: number, mailbox: string) => { return data; }; -// Unarchive message export const unarchiveMessage = async (messageId: number, mailbox: string) => { const { data } = await axios.patch( `/email/messages/${messageId}/unarchive?mailbox=${mailbox}` @@ -107,7 +95,6 @@ export const unarchiveMessage = async (messageId: number, mailbox: string) => { return data; }; -// Restore message from trash export const restoreMessage = async (messageId: number, mailbox: string) => { const { data } = await axios.patch( `/email/messages/${messageId}/restore?mailbox=${mailbox}` diff --git a/src/shared/SideBar.tsx b/src/shared/SideBar.tsx index 66e391c..e39d302 100644 --- a/src/shared/SideBar.tsx +++ b/src/shared/SideBar.tsx @@ -31,7 +31,6 @@ const SideBar: FC = () => { const iconSizeSideBar = 20 - // if (!mailboxCount?.data) return null return ( <> {