From a5724369dae537cc3518a5f6d03713a085ef104e Mon Sep 17 00:00:00 2001 From: morteza-mortezai Date: Fri, 17 Jul 2026 20:18:59 +0330 Subject: [PATCH] order detail --- src/components/MultiSelect.tsx | 169 ++++++++++++++++++ src/components/UploadBox.tsx | 2 +- src/pages/admin/Create.tsx | 50 ++++-- src/pages/admin/List.tsx | 15 ++ src/pages/admin/Update.tsx | 66 +++++-- src/pages/admin/types/Types.ts | 2 + src/pages/order/ConvertToOrders.tsx | 23 ++- src/pages/order/EditOrder.tsx | 45 +++-- .../order/components/OrderDetailSidebar.tsx | 54 ++++-- .../order/components/OrderListColumns.tsx | 24 ++- src/pages/order/types/Types.ts | 16 +- src/pages/user/Create.tsx | 46 +++-- src/pages/user/List.tsx | 8 + src/pages/user/Update.tsx | 62 +++++-- src/pages/user/types/Types.ts | 2 + src/shared/Sidebar.tsx | 2 +- 16 files changed, 481 insertions(+), 105 deletions(-) create mode 100644 src/components/MultiSelect.tsx diff --git a/src/components/MultiSelect.tsx b/src/components/MultiSelect.tsx new file mode 100644 index 0000000..e2cfc6c --- /dev/null +++ b/src/components/MultiSelect.tsx @@ -0,0 +1,169 @@ +import { useEffect, useRef, useState, type FC, type MouseEvent } from 'react' +import { ArrowDown2, CloseCircle, TickSquare } from 'iconsax-react' +import { clx } from '../helpers/utils' +import type { ItemsSelectType } from './Select' + +type Props = { + className?: string + items: ItemsSelectType[] + value: string[] + onChange: (value: string[]) => void + onBlur?: () => void + error_text?: string + placeholder?: string + label?: string + disabled?: boolean +} + +const MultiSelect: FC = ({ + className, + items, + value, + onChange, + onBlur, + error_text, + placeholder = 'انتخاب کنید', + label, + disabled, +}) => { + const [isOpen, setIsOpen] = useState(false) + const wrapperRef = useRef(null) + const selectedValues = value ?? [] + + useEffect(() => { + const handleClickOutside = (e: MouseEvent) => { + if (wrapperRef.current && !wrapperRef.current.contains(e.target as Node)) { + if (isOpen) { + setIsOpen(false) + onBlur?.() + } + } + } + document.addEventListener('mousedown', handleClickOutside) + return () => document.removeEventListener('mousedown', handleClickOutside) + }, [isOpen, onBlur]) + + const selectedItems = items.filter((item) => + selectedValues.includes(String(item.value)), + ) + + const toggleValue = (itemValue: string) => { + if (selectedValues.includes(itemValue)) { + onChange(selectedValues.filter((v) => v !== itemValue)) + } else { + onChange([...selectedValues, itemValue]) + } + } + + const handleClear = (e: MouseEvent) => { + e.stopPropagation() + onChange([]) + onBlur?.() + } + + const displayText = + selectedItems.length === 0 + ? placeholder + : selectedItems.length <= 2 + ? selectedItems.map((item) => item.label).join('، ') + : `${selectedItems.length} مورد انتخاب شده` + + return ( +
+ {label && ( + + )} +
+ + {selectedItems.length > 0 && ( + + )} + {isOpen && ( +
+ {items.length === 0 ? ( +
+ موردی برای انتخاب نیست +
+ ) : ( +
    + {items.map((item) => { + const itemValue = String(item.value) + const isSelected = selectedValues.includes(itemValue) + return ( +
  • + +
  • + ) + })} +
+ )} +
+ )} +
+ {selectedItems.length > 0 && ( +
+ {selectedItems.map((item) => ( + + {item.label} + + + ))} +
+ )} + {error_text ? ( +
+ {error_text} +
+ ) : null} +
+ ) +} + +export default MultiSelect diff --git a/src/components/UploadBox.tsx b/src/components/UploadBox.tsx index 5bbe78d..6da5e75 100644 --- a/src/components/UploadBox.tsx +++ b/src/components/UploadBox.tsx @@ -50,7 +50,7 @@ const UploadBox: FC = (props: Props) => {
{props.label}
-