revamp template

This commit is contained in:
fro1991
2025-02-01 16:44:51 +07:00
parent c432df568a
commit 276a289580
1212 changed files with 112762 additions and 0 deletions

View File

@ -0,0 +1,22 @@
import { toAbsoluteUrl } from '@/utils';
interface IChatMessageInProps {
text: string;
time: string;
}
const ChatMessageIn = ({ text, time }: IChatMessageInProps) => {
return (
<div className="flex items-end gap-3.5 px-5">
<div className="flex flex-col gap-1.5">
<div
className="card shadow-none flex flex-col bg-gray-100 gap-2.5 p-3 rounded-bl-none text-2sm font-medium text-gray-700"
dangerouslySetInnerHTML={{ __html: text }}
/>
<span className="text-2xs font-medium text-gray-500">{time}</span>
</div>
</div>
);
};
export { ChatMessageIn, type IChatMessageInProps };

View File

@ -0,0 +1,27 @@
import { toAbsoluteUrl } from '@/utils';
import { KeenIcon } from '@/components';
import clsx from 'clsx';
interface IChatMessageOutProps {
text: string;
time: string;
}
const ChatMessageOut = ({ text, time }: IChatMessageOutProps) => {
return (
<div className="flex items-end justify-end gap-3.5 px-5">
<div className="flex flex-col gap-1.5">
<div
className="card shadow-none flex bg-primary text-primary-inverse text-2sm font-medium flex-col gap-2.5 p-3 rounded-be-none"
dangerouslySetInnerHTML={{ __html: text }}
/>
<div className="flex items-center justify-end relative">
<span className="text-2xs font-medium text-gray-600 me-6">{time}</span>
</div>
</div>
</div>
);
};
export { ChatMessageOut, type IChatMessageOutProps };

View File

@ -0,0 +1,58 @@
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { Calendar } from '@/components/ui/calendar';
import { format } from 'date-fns';
import { KeenIcon } from '@/components/keenicons';
import { cn } from '@/lib/utils';
interface DatePickerProps {
date?: Date;
setDate: (date: Date) => void;
value?: string;
onChange?: (e: { target: { value: string } }) => void;
className?: string; // Tambahkan className sebagai props
}
const DatePicker = ({
date = new Date(),
setDate,
value,
onChange,
className
}: DatePickerProps) => {
const handleDateSelect = (selectedDate: Date | undefined) => {
if (selectedDate) {
setDate(selectedDate);
if (onChange) {
onChange({ target: { value: format(selectedDate, 'yyyy-MM-dd') } });
}
}
};
return (
<Popover>
<PopoverTrigger asChild>
<button
className={cn(
'btn btn-sm btn-light data-[state=open]:bg-light-active w-full',
!date && 'text-gray-400',
className // Terapkan className di sini
)}
>
<KeenIcon icon="calendar" className="me-0.5 mb-0.5 text-info" />
{value || (date ? format(date, 'yyyy-MM-dd') : 'Pilih Tanggal')}
</button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="end">
<Calendar
mode="single"
selected={date}
onSelect={handleDateSelect}
defaultMonth={date}
numberOfMonths={1}
/>
</PopoverContent>
</Popover>
);
};
export { DatePicker };

View File

@ -0,0 +1,60 @@
import { useState, useEffect } from 'react';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { Calendar } from '@/components/ui/calendar';
import { DateRange } from 'react-day-picker';
import { format, subDays } from 'date-fns';
import { KeenIcon } from '@/components/keenicons';
import { cn } from '@/lib/utils';
interface DateRangePickerProps {
date: DateRange | undefined;
setDate: (date: DateRange | undefined) => void;
}
const DateRangePicker = ({ date, setDate }: DateRangePickerProps) => {
useEffect(() => {
if (!date) {
const today = new Date();
const last30Days = subDays(today, 30);
setDate({ from: last30Days, to: today });
}
}, [date, setDate]);
return (
<Popover>
<PopoverTrigger asChild>
<button
id="date"
className={cn(
'btn btn-sm btn-light data-[state=open]:bg-light-active w-full',
!date && 'text-gray-400'
)}
>
<KeenIcon icon="calendar" className="me-0.5" />
{date?.from ? (
date.to ? (
<>
{format(date.from, 'LLL dd, y')} - {format(date.to, 'LLL dd, y')}
</>
) : (
format(date.from, 'LLL dd, y')
)
) : (
<span>Pick a date range</span>
)}
</button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="end">
<Calendar
initialFocus
mode="range"
defaultMonth={date?.from}
selected={date}
onSelect={setDate}
numberOfMonths={2}
/>
</PopoverContent>
</Popover>
);
};
export { DateRangePicker };

View File

@ -0,0 +1,293 @@
import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components';
import { useCreditListContext } from '../hooks';
import { useNavigate } from 'react-router';
import { Button } from '@/components/ui/button';
import { DateRangePicker } from './DateRangePicker';
import { useState, useEffect } from 'react';
import { DateRange } from 'react-day-picker';
import XlsIcon from '@/public_media/file-types/xls.svg';
import { toAbsoluteUrl } from '@/utils';
import { toast } from 'sonner';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue
} from '@/components/ui/select';
import {
DropdownMenuCheckboxItem,
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent
} from '@/components/ui/dropdown-menu';
const ListToolBar = ({ setFilter }: any) => {
const navigate = useNavigate();
const { table, reload } = useDataGrid();
const { date, setDate, doExportData } = useCreditListContext();
const [filteredDate, setFilteredDate] = useState<DateRange | null>(null);
const [selectedStatus, setSelectedStatus] = useState<string[]>([]);
const [isStatusDropdownOpen, setIsStatusDropdownOpen] = useState(false);
const [debitorName, setDebitorName] = useState('');
const [company, setCompany] = useState('');
const [code, setCode] = useState('');
const [employeeId, setEmployeeId] = useState('');
const handleReload = () => {
reload();
};
const handleFilterData = () => {
try {
const filters = [];
if (selectedStatus.length > 0) {
filters.push({
id: 'a.status',
value: selectedStatus
});
}
if (debitorName != '') filters.push({ id: 'debtor.name', value: `%${debitorName}%` });
if (company != '') filters.push({ id: 'company.name', value: `%${company}%` });
if (employeeId != '') filters.push({ id: 'debtor.employee_id', value: `%${employeeId}%` });
if (code != '') {
filters.push({ id: 'a.code', value: code });
}
if (date?.from && date?.to) {
setFilteredDate({
from: date.from,
to: date.to
});
filters.push({
id: 'application_date_from',
value: date.from.toISOString().split('T')[0]
});
filters.push({
id: 'application_date_to',
value: date.to.toISOString().split('T')[0]
});
table.setColumnFilters(filters);
}
} catch (error) {
toast.error('Error filter data');
}
};
const handleResetData = () => {
setDate({
from: new Date(new Date().setDate(new Date().getDate() - 31)),
to: new Date()
});
setFilteredDate(null);
setSelectedStatus([]);
setCode('');
table.setColumnFilters([]);
reload();
};
const handleCreateNew = () => {
navigate('/pengajuan_kredit/list/add');
};
const handleExport = () => {
const sorting = table.getState().sorting;
doExportData(sorting, table.getState().columnFilters);
};
const handleStatusChange = (statusId: string) => {
console.log('statusId :', statusId);
setSelectedStatus((prev) =>
prev.includes(statusId) ? prev.filter((id) => id != statusId) : [...prev, statusId]
);
};
const handleStatusDropdownOpen = () => {
setIsStatusDropdownOpen(true);
};
const handleStatusDropdownClose = () => {
setIsStatusDropdownOpen(false);
};
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
handleStatusDropdownClose();
};
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [handleStatusDropdownClose]);
return (
<div className="card-header flex-wrap gap-2 border-b-0 px-5">
<div className="flex flex-wrap gap-2 lg:gap-5 w-full">
<div className="flex justify-between w-full items-center">
<div className="flex gap-3 items-center">
<div className="w-auto min-w-[220px]">
<DateRangePicker date={date} setDate={setDate} />
</div>
<div className="w-auto min-w-[150px]">
<DropdownMenu open={isStatusDropdownOpen} onOpenChange={handleStatusDropdownOpen}>
<DropdownMenuTrigger asChild>
<Button variant="outline" className="h-7.5 text-[0.8rem] w-full justify-between">
{selectedStatus.length > 0
? `Select Status: ${selectedStatus.length}`
: 'Select Status'}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuCheckboxItem
key="open"
checked={selectedStatus.includes('open')}
onCheckedChange={() => handleStatusChange('open')}
onMouseDown={(e) => {
e.preventDefault();
e.stopPropagation();
}}
className="justify-between h-6 text-[0.8rem]"
>
OPEN
</DropdownMenuCheckboxItem>
<DropdownMenuCheckboxItem
key="under_review"
checked={selectedStatus.includes('under_review')}
onCheckedChange={() => handleStatusChange('under_review')}
onMouseDown={(e) => {
e.preventDefault();
e.stopPropagation();
}}
className="justify-between h-6 text-[0.8rem]"
>
UNDER REVIEW
</DropdownMenuCheckboxItem>
{/* <DropdownMenuCheckboxItem
key="revision"
checked={selectedStatus.includes('revision')}
onCheckedChange={() => handleStatusChange('revision')}
onMouseDown={(e) => {
e.preventDefault();
e.stopPropagation();
}}
className="justify-between h-6 text-[0.8rem]"
>
REVISON
</DropdownMenuCheckboxItem> */}
<DropdownMenuCheckboxItem
key="approved"
checked={selectedStatus.includes('approved')}
onCheckedChange={() => handleStatusChange('approved')}
onMouseDown={(e) => {
e.preventDefault();
e.stopPropagation();
}}
className="justify-between h-6 text-[0.8rem]"
>
APPROVE
</DropdownMenuCheckboxItem>
<DropdownMenuCheckboxItem
key="rejected"
checked={selectedStatus.includes('rejected')}
onCheckedChange={() => handleStatusChange('rejected')}
onMouseDown={(e) => {
e.preventDefault();
e.stopPropagation();
}}
className="justify-between h-6 text-[0.8rem]"
>
REJECT
</DropdownMenuCheckboxItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
<div className="w-auto min-w-[100px]">
<label className="input input-sm">
<KeenIcon icon="filter" />
<input
type="text"
placeholder="Code"
value={code}
onChange={(event) => setCode(event.target.value)}
/>
</label>
</div>
<div className="w-auto min-w-[100px]">
<label className="input input-sm">
<KeenIcon icon="filter" />
<input
type="text"
placeholder="Company"
value={company}
onChange={(event) => setCompany(event.target.value)}
/>
</label>
</div>
<div className="w-auto min-w-[100px]">
<label className="input input-sm">
<KeenIcon icon="filter" />
<input
type="text"
placeholder="Debitor Name"
value={debitorName}
onChange={(event) => setDebitorName(event.target.value)}
/>
</label>
</div>
<div className="w-auto min-w-[100px]">
<label className="input input-sm">
<KeenIcon icon="filter" />
<input
type="text"
placeholder="Employee ID"
value={employeeId}
onChange={(event) => setEmployeeId(event.target.value)}
/>
</label>
</div>
<div className="flex item-center gap-3 ms-2 me-10">
<DefaultTooltip title={'Filter'} placement={'top'}>
<Button variant="outline" className="h-7.5" onClick={handleFilterData}>
<KeenIcon icon="filter" />
</Button>
</DefaultTooltip>
<DefaultTooltip title={'Reset Filter'} placement={'top'}>
<Button variant="outline" className="h-7.5" onClick={handleResetData}>
<KeenIcon icon="arrow-circle-left" />
</Button>
</DefaultTooltip>
</div>
</div>
<div className="flex gap-3 items-center">
{/* <Button
variant="outline"
className="h-7.5 text-[0.8rem]"
onClick={() => handleCreateNew()}
>
Add Data
</Button> */}
<DefaultTooltip title={'Export Data'} placement={'top'}>
<Button variant={'outline'} className="h-7.5 min-w-[58px]" onClick={handleExport}>
<img src={toAbsoluteUrl('/media/file-types/xls.svg')} className="" alt="" />
</Button>
</DefaultTooltip>
<DefaultTooltip title={'Refresh'} placement={'top'}>
<Button variant="outline" className="h-7.5" onClick={handleReload}>
<KeenIcon icon="arrows-circle" />
</Button>
</DefaultTooltip>
</div>
</div>
</div>
</div>
);
};
export { ListToolBar };

View File

@ -0,0 +1,49 @@
import { toAbsoluteUrl } from '@/utils';
import { useState } from 'react';
interface IDropdownNotificationsItemProps {
userName: string;
avatar: string;
description: string;
time: string;
text: string;
company: string;
}
const Notes = ({
userName,
avatar,
description,
time,
text,
company
}: IDropdownNotificationsItemProps) => {
const [emailInput, setEmailInput] = useState('');
return (
<div className="flex grow gap-2.5">
<div className="relative shrink-0 mt-0.5">
<img className="h-[20px] max-w-none" src={toAbsoluteUrl(avatar)} alt="logo" />
</div>
<div className="flex flex-col gap-1 w-full">
<div className="flex flex-col gap-1">
<div className="text-2sm font-medium flex justify-between">
<p className="text-gray-900 font-semibold">{userName}</p>
<span className="text-gray-700"> {description} </span>
<span className="flex items-center text-2xs font-medium text-gray-500">{time}</span>
</div>
</div>
<div
className="card shadow-none flex flex-col gap-2.5 p-3.5 rounded-lg bg-light-active"
style={{ borderColor: company == 'BRI' ? '#02529c' : '' }}
>
<div className="text-2sm font-semibold text-gray-600 mb-px">
<span className="text-gray-700 font-medium"> {text} </span>
</div>
</div>
</div>
</div>
);
};
export { Notes };

View File

@ -0,0 +1,6 @@
export * from './ListToolBar';
export * from './DateRangePicker';
export * from './DatePicker';
export * from './ChatMessageIn';
export * from './ChatMessageOut';
export * from './Notes'