manage users

This commit is contained in:
hamid zarghami
2026-06-17 10:40:59 +03:30
parent a03a147d12
commit 908f5e72ed
9 changed files with 214 additions and 109 deletions
+83 -93
View File
@@ -1,115 +1,105 @@
import { FC, InputHTMLAttributes, useEffect, useState } from 'react'
import { clx } from '../helpers/utils';
import EyeIcon from '../assets/images/eye.svg'
import { SearchNormal } from 'iconsax-react';
import Error from './Error';
import { SearchNormal } from "iconsax-react";
import { FC, InputHTMLAttributes, useEffect, useState } from "react";
import EyeIcon from "../assets/images/eye.svg";
import { clx } from "../helpers/utils";
import Error from "./Error";
type Variant = "floating_outlined" | "primary" | "search";
type Props = {
label?: string;
className?: string;
variant?: Variant;
error_text?: string;
onEnter?: () => void;
unit?: string;
seprator?: boolean;
isNotRequired?: boolean;
onChangeSearchFinal?: (value: string) => void;
} & InputHTMLAttributes<HTMLInputElement>
label?: string;
className?: string;
variant?: Variant;
error_text?: string;
onEnter?: () => void;
unit?: string;
seprator?: boolean;
isNotRequired?: boolean;
onChangeSearchFinal?: (value: string) => void;
labelClassName?: string;
} & InputHTMLAttributes<HTMLInputElement>;
const formatNumber = (value: string | number): string => {
if (!value) return '';
const inputValue = String(value).replace(/,/g, '');
return inputValue.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
if (!value) return "";
const inputValue = String(value).replace(/,/g, "");
return inputValue.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
};
const Input: FC<Props> = (props: Props) => {
const [formattedValue, setFormattedValue] = useState<string>(props.value ? formatNumber(props.value as string) : "");
const [formattedValue, setFormattedValue] = useState<string>(
props.value ? formatNumber(props.value as string) : ''
);
const [showPassword, setShowPassword] = useState<boolean>(false);
const [search, setSearch] = useState<string>("");
const [showPassword, setShowPassword] = useState<boolean>(false)
const [search, setSearch] = useState<string>('')
const inputClass = clx(
"w-full h-10 text-black block px-4 text-xs rounded-xl border border-border",
props.readOnly && "bg-gray-100 border-0 text-description",
props.variant === "search" && "bg-[#EEF0F7] border-0 ps-10",
props.className,
);
const inputClass = clx(
'w-full h-10 text-black block px-4 text-xs rounded-xl border border-border',
props.readOnly && 'bg-gray-100 border-0 text-description',
props.variant === 'search' && 'bg-[#EEF0F7] border-0 ps-10',
props.className
);
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
if (props.seprator) {
const inputValue = event.target.value.replace(/,/g, ""); // حذف کاماها
const formatted = formatNumber(inputValue);
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
if (props.seprator) {
const inputValue = event.target.value.replace(/,/g, ''); // حذف کاماها
const formatted = formatNumber(inputValue);
// به‌روزرسانی مقدار قالب‌بندی‌شده
setFormattedValue(formatted);
// به‌روزرسانی مقدار قالب‌بندی‌شده
setFormattedValue(formatted);
// ارسال مقدار خام به `onChange` والد
props.onChange?.({
...event,
target: {
...event.target,
value: inputValue,
},
});
} else {
props.onChange?.(event);
}
};
// ارسال مقدار خام به `onChange` والد
props.onChange?.({
...event,
target: {
...event.target,
value: inputValue,
},
});
} else {
props.onChange?.(event);
}
};
useEffect(() => {
if (props.value) {
setFormattedValue(formatNumber(props.value as string));
} else {
setFormattedValue("");
}
}, [props.value]);
useEffect(() => {
if (props.value) {
setFormattedValue(formatNumber(props.value as string));
} else {
setFormattedValue('');
}
}, [props.value])
useEffect(() => {
if (props.variant === "search" && props.onChangeSearchFinal) {
const timeout = setTimeout(() => {
props.onChangeSearchFinal?.(search);
}, 1000);
return () => clearTimeout(timeout);
}
}, [search, props]);
useEffect(() => {
if (props.variant === 'search' && props.onChangeSearchFinal) {
const timeout = setTimeout(() => {
props.onChangeSearchFinal?.(search)
}, 1000)
return () => clearTimeout(timeout)
}
}, [search, props])
return (
<div className="w-full">
<label className={clx("text-sm", props.labelClassName)}>{props.label}</label>
<div className="w-full relative mt-1">
<input
{...props}
onChange={(e) => {
setSearch(e.target.value);
handleInputChange(e);
}}
value={props.seprator ? formattedValue : props.value}
type={props.type === "password" && showPassword ? "text" : props.type === "password" ? "password" : undefined}
className={inputClass}
/>
return (
<div className='w-full'>
<label className='text-sm'>
{props.label}
</label>
{props.type === "password" && <img onClick={() => setShowPassword((oldValue) => !oldValue)} src={EyeIcon} className="w-5 absolute top-0 bottom-0 cursor-pointer my-auto left-3" />}
<div className='w-full relative mt-1'>
<input {...props} onChange={(e) => {
setSearch(e.target.value)
handleInputChange(e)
}} value={props.seprator ? formattedValue : props.value} type={props.type === 'password' && showPassword ? 'text' : props.type === 'password' ? 'password' : undefined} className={inputClass} />
{props.variant === "search" && <SearchNormal size={20} color="#8C90A3" className="absolute top-0 w-5 bottom-0 my-auto right-3" />}
{
props.type === 'password' &&
<img onClick={() => setShowPassword((oldValue) => !oldValue)} src={EyeIcon} className='w-5 absolute top-0 bottom-0 cursor-pointer my-auto left-3' />
}
{props.error_text && <Error errorText={props.error_text} />}
</div>
</div>
);
};
{
props.variant === 'search' &&
<SearchNormal size={20} color='#8C90A3' className='absolute top-0 w-5 bottom-0 my-auto right-3' />
}
{
props.error_text &&
<Error
errorText={props.error_text}
/>
}
</div>
</div>
)
}
export default Input
export default Input;