hold action mobile + najva token updated
This commit is contained in:
+87
-24
@@ -1,4 +1,4 @@
|
||||
import React, { Fragment, useState } from 'react';
|
||||
import React, { Fragment, useState, useRef } from 'react';
|
||||
import DefaultTableSkeleton from './DefaultTableSkeleton';
|
||||
import Td from './Td';
|
||||
import { TableProps, RowDataType, ColumnType } from './types/TableTypes';
|
||||
@@ -31,6 +31,9 @@ const Table = <T extends RowDataType>({
|
||||
}: TableProps<T>): React.ReactElement => {
|
||||
|
||||
const [internalSelectedRows, setInternalSelectedRows] = useState<T[]>([]);
|
||||
const [mobileSelectionMode, setMobileSelectionMode] = useState(false);
|
||||
const longPressTimer = useRef<number | null>(null);
|
||||
const [longPressActiveId, setLongPressActiveId] = useState<string | number | null>(null);
|
||||
|
||||
// استفاده از selectedRows خارجی اگر موجود باشد، در غیر این صورت از internal استفاده کن
|
||||
const selectedRows = externalSelectedRows !== undefined ? externalSelectedRows : internalSelectedRows;
|
||||
@@ -40,8 +43,59 @@ const Table = <T extends RowDataType>({
|
||||
if (clearSelection && externalSelectedRows === undefined) {
|
||||
setInternalSelectedRows([]);
|
||||
}
|
||||
// خروج از حالت انتخاب موبایل هم
|
||||
if (clearSelection) {
|
||||
setMobileSelectionMode(false);
|
||||
}
|
||||
}, [clearSelection, externalSelectedRows]);
|
||||
|
||||
// تمیز کردن timer هنگام unmount
|
||||
React.useEffect(() => {
|
||||
return () => {
|
||||
if (longPressTimer.current) {
|
||||
clearTimeout(longPressTimer.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
// خروج از حالت انتخاب اگر هیچ آیتمی انتخاب نشده
|
||||
React.useEffect(() => {
|
||||
if (selectedRows.length === 0 && mobileSelectionMode) {
|
||||
setMobileSelectionMode(false);
|
||||
}
|
||||
}, [selectedRows.length, mobileSelectionMode]);
|
||||
|
||||
const handleLongPressStart = (item: T) => {
|
||||
if (!selectable || mobileSelectionMode) return;
|
||||
|
||||
setLongPressActiveId(item.id);
|
||||
longPressTimer.current = window.setTimeout(() => {
|
||||
setMobileSelectionMode(true);
|
||||
// انتخاب آیتم فعلی
|
||||
handleSingleRowSelect(item, true);
|
||||
setLongPressActiveId(null);
|
||||
}, 500); // 500ms برای long press
|
||||
};
|
||||
|
||||
const handleLongPressEnd = () => {
|
||||
if (longPressTimer.current) {
|
||||
clearTimeout(longPressTimer.current);
|
||||
longPressTimer.current = null;
|
||||
}
|
||||
setLongPressActiveId(null);
|
||||
};
|
||||
|
||||
const handleMobileRowClick = (item: T) => {
|
||||
if (mobileSelectionMode) {
|
||||
// در حالت انتخاب، آیتم را انتخاب/عدم انتخاب کن
|
||||
const isSelected = isRowSelected(item);
|
||||
handleSingleRowSelect(item, !isSelected);
|
||||
} else if (longPressActiveId !== item.id) {
|
||||
// در حالت عادی، row click عادی را اجرا کن
|
||||
handleRowClick(item);
|
||||
}
|
||||
};
|
||||
|
||||
const getRowClassName = (item: T, index: number): string => {
|
||||
if (typeof rowClassName === 'function') {
|
||||
return rowClassName(item, index);
|
||||
@@ -136,36 +190,24 @@ const Table = <T extends RowDataType>({
|
||||
return (
|
||||
<div
|
||||
key={item.id}
|
||||
className={`w-full min-h-[85px] ${bgColor} ${hoverColor} ${onRowClick ? 'cursor-pointer' : ''} ${getRowClassName(item, rowIndex)} px-4 py-3 flex items-center gap-3 ${rowIndex !== 0 ? 'border-t border-[#EAEDF5]' : ''}`}
|
||||
onClick={() => handleRowClick(item)}
|
||||
className={`w-full min-h-[85px] ${bgColor} ${hoverColor} ${mobileSelectionMode || !onRowClick ? '' : 'cursor-pointer'} ${getRowClassName(item, rowIndex)} px-4 py-3 flex items-center gap-3 ${rowIndex !== 0 ? 'border-t border-[#EAEDF5]' : ''} ${longPressActiveId === item.id ? 'bg-blue-50' : ''}`}
|
||||
onClick={() => handleMobileRowClick(item)}
|
||||
onTouchStart={() => handleLongPressStart(item)}
|
||||
onTouchEnd={handleLongPressEnd}
|
||||
onTouchCancel={handleLongPressEnd}
|
||||
onMouseDown={() => handleLongPressStart(item)}
|
||||
onMouseUp={handleLongPressEnd}
|
||||
onMouseLeave={handleLongPressEnd}
|
||||
>
|
||||
{selectable && (
|
||||
{selectable && mobileSelectionMode && (
|
||||
<div
|
||||
className="flex-shrink-0 "
|
||||
className="flex-shrink-0"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<Checkbox
|
||||
checked={isRowSelected(item)}
|
||||
onCheckedChange={(checked) => handleSingleRowSelect(item, !!checked)}
|
||||
/>
|
||||
|
||||
{/* {inlineActions && (
|
||||
<div
|
||||
className="flex-shrink-0 flex items-center gap-2 "
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{inlineActions(item).map((action, actionIndex) => (
|
||||
<div
|
||||
key={actionIndex}
|
||||
className={`cursor-pointer ${action.className || ''}`}
|
||||
onClick={action.onClick}
|
||||
title={action.tooltip}
|
||||
>
|
||||
{action.icon}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)} */}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -341,11 +383,32 @@ const Table = <T extends RowDataType>({
|
||||
{/* نسخه موبایل - Gmail style */}
|
||||
<div className={`md:hidden`}>
|
||||
{(actionsPosition === 'top' || actionsPosition === 'above-header') && (
|
||||
<div className="h-[64px] bg-white flex items-center px-4 rounded-t-2xl border-b border-[#EAEDF5]">
|
||||
<div className="h-[64px] bg-white flex items-center justify-between px-4 rounded-t-2xl border-b border-[#EAEDF5]">
|
||||
<div className='flex items-center gap-2'>
|
||||
{actions}
|
||||
{selectable && selectedRows.length > 0 && selectedActions && selectedActions}
|
||||
</div>
|
||||
{mobileSelectionMode && (
|
||||
<button
|
||||
onClick={() => {
|
||||
setMobileSelectionMode(false);
|
||||
// پاک کردن انتخابها
|
||||
if (externalSelectedRows !== undefined) {
|
||||
if (onSelectionChange) {
|
||||
onSelectionChange([]);
|
||||
}
|
||||
} else {
|
||||
setInternalSelectedRows([]);
|
||||
if (onSelectionChange) {
|
||||
onSelectionChange([]);
|
||||
}
|
||||
}
|
||||
}}
|
||||
className="text-sm text-gray-600 px-3 py-1"
|
||||
>
|
||||
انصراف
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{renderGmailStyleRows()}
|
||||
|
||||
Reference in New Issue
Block a user