2nd
This commit is contained in:
@@ -11,6 +11,9 @@ import {
|
||||
Fade,
|
||||
Chip,
|
||||
Card,
|
||||
Skeleton,
|
||||
CircularProgress,
|
||||
Backdrop,
|
||||
} from '@mui/material';
|
||||
import {
|
||||
Add,
|
||||
@@ -42,6 +45,16 @@ const TodosPage = () => {
|
||||
const [viewMode, setViewMode] = useState<ViewMode>('list');
|
||||
const [filterMode, setFilterMode] = useState<FilterMode>('all');
|
||||
const [showFilters, setShowFilters] = useState(false);
|
||||
const [appliedFilters, setAppliedFilters] = useState({
|
||||
status: [] as string[],
|
||||
priority: [] as string[],
|
||||
assignee: '',
|
||||
dateFrom: null as any,
|
||||
dateTo: null as any,
|
||||
starred: false,
|
||||
overdue: false,
|
||||
dueSoon: false,
|
||||
});
|
||||
const [showSearch, setShowSearch] = useState(false);
|
||||
const [selectedTodos, setSelectedTodos] = useState<string[]>([]);
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
@@ -142,10 +155,68 @@ const TodosPage = () => {
|
||||
case 'following':
|
||||
return todo.followers?.includes(currentUser.ad_account) || false;
|
||||
default:
|
||||
return true;
|
||||
break; // 繼續其他篩選
|
||||
}
|
||||
}
|
||||
|
||||
// 進階篩選
|
||||
// 狀態篩選
|
||||
if (appliedFilters.status.length > 0 && !appliedFilters.status.includes(todo.status)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 優先級篩選
|
||||
if (appliedFilters.priority.length > 0 && !appliedFilters.priority.includes(todo.priority)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 指派人篩選
|
||||
if (appliedFilters.assignee && currentUser) {
|
||||
switch (appliedFilters.assignee) {
|
||||
case 'me':
|
||||
if (!todo.responsible_users?.includes(currentUser.ad_account)) return false;
|
||||
break;
|
||||
case 'created_by_me':
|
||||
if (todo.creator_ad !== currentUser.ad_account) return false;
|
||||
break;
|
||||
case 'followed_by_me':
|
||||
if (!todo.followers?.includes(currentUser.ad_account)) return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 日期篩選
|
||||
if (appliedFilters.dateFrom || appliedFilters.dateTo) {
|
||||
if (!todo.due_date) return false;
|
||||
const dueDate = new Date(todo.due_date);
|
||||
if (appliedFilters.dateFrom && dueDate < new Date(appliedFilters.dateFrom)) return false;
|
||||
if (appliedFilters.dateTo && dueDate > new Date(appliedFilters.dateTo)) return false;
|
||||
}
|
||||
|
||||
// 星號篩選
|
||||
if (appliedFilters.starred && !todo.starred) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 逾期篩選
|
||||
if (appliedFilters.overdue) {
|
||||
if (!todo.due_date) return false;
|
||||
const dueDate = new Date(todo.due_date);
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
if (dueDate >= today || todo.status === 'DONE') return false;
|
||||
}
|
||||
|
||||
// 即將到期篩選
|
||||
if (appliedFilters.dueSoon) {
|
||||
if (!todo.due_date || todo.status === 'DONE') return false;
|
||||
const dueDate = new Date(todo.due_date);
|
||||
const today = new Date();
|
||||
const threeDaysFromNow = new Date();
|
||||
threeDaysFromNow.setDate(today.getDate() + 3);
|
||||
if (dueDate < today || dueDate > threeDaysFromNow) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -544,7 +615,11 @@ const TodosPage = () => {
|
||||
exit={{ opacity: 0, height: 0, marginBottom: 0 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
<TodoFilters onClose={() => setShowFilters(false)} />
|
||||
<TodoFilters
|
||||
onClose={() => setShowFilters(false)}
|
||||
onApply={setAppliedFilters}
|
||||
initialFilters={appliedFilters}
|
||||
/>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
@@ -572,8 +647,28 @@ const TodosPage = () => {
|
||||
{/* 主要內容區域 */}
|
||||
<motion.div variants={itemVariants}>
|
||||
<Fade in={true} timeout={500}>
|
||||
<Box>
|
||||
{viewMode === 'list' ? (
|
||||
<Box sx={{ position: 'relative', minHeight: '400px' }}>
|
||||
{loading ? (
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
||||
{Array.from({ length: 3 }).map((_, index) => (
|
||||
<Card key={index} sx={{ p: 3 }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2, mb: 2 }}>
|
||||
<Skeleton variant="rectangular" width={20} height={20} />
|
||||
<Skeleton variant="text" width="60%" height={32} />
|
||||
<Skeleton variant="circular" width={24} height={24} sx={{ ml: 'auto' }} />
|
||||
</Box>
|
||||
<Skeleton variant="text" width="80%" height={20} sx={{ mb: 1 }} />
|
||||
<Skeleton variant="text" width="40%" height={20} sx={{ mb: 2 }} />
|
||||
<Box sx={{ display: 'flex', gap: 1, mb: 2 }}>
|
||||
<Skeleton variant="rounded" width={60} height={24} />
|
||||
<Skeleton variant="rounded" width={50} height={24} />
|
||||
<Skeleton variant="rounded" width={70} height={24} />
|
||||
</Box>
|
||||
<Skeleton variant="text" width="30%" height={16} />
|
||||
</Card>
|
||||
))}
|
||||
</Box>
|
||||
) : viewMode === 'list' ? (
|
||||
<TodoList
|
||||
todos={filteredTodos}
|
||||
selectedTodos={selectedTodos}
|
||||
|
Reference in New Issue
Block a user