improvement: some new gadgets added to dashboard. some new functionality added to existed gadgets.

This commit is contained in:
2026-07-14 03:06:56 +03:30
parent ec2b23f4b1
commit d383a4abc3
34 changed files with 944 additions and 191 deletions

View File

@@ -1,6 +1,7 @@
'use client';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useSearchParams } from 'next/navigation';
import { useTranslations } from 'next-intl';
import { Button } from '@/components/ui/shared/Button';
import { Checkbox } from '@/components/ui/shared/Checkbox';
@@ -16,6 +17,7 @@ import {
isDefaultTasksView,
TASK_COMPLETE_EXIT_MS,
} from '@/components/lab/tasksViewDefaults';
import { parseTasksSearchParams } from '@/components/lab/parseTasksSearchParams';
import { useMarkTabReadOnVisit } from '@/lib/hooks/useTabBadgeCounts';
import { notifyTabBadgesChanged } from '@/lib/tabBadgeUtils';
import { scrollWithinMainScrollContainer } from '@/components/shared/scrollWithinMain';
@@ -40,6 +42,7 @@ const PAGE_SIZE = 50;
export function TasksPage() {
const t = useTranslations('tasks');
const tErrors = useTranslations('errors');
const searchParams = useSearchParams();
const { currentOrganization, user, isAuthReady } = useAuth();
const { showError, showSuccess, setError } = useToast();
@@ -71,6 +74,10 @@ export function TasksPage() {
const [importantOnly, setImportantOnly] = useState(DEFAULT_TASKS_VIEW.importantOnly);
const [assignedToMe, setAssignedToMe] = useState(DEFAULT_TASKS_VIEW.assignedToMe);
const [overdueOnly, setOverdueOnly] = useState(DEFAULT_TASKS_VIEW.overdueOnly);
const [unassignedOnly, setUnassignedOnly] = useState(DEFAULT_TASKS_VIEW.unassignedOnly);
const [prosthesisTypeCode, setProsthesisTypeCode] = useState(
DEFAULT_TASKS_VIEW.prosthesisTypeCode,
);
const [sortBy, setSortBy] = useState<TaskSortField>(DEFAULT_TASKS_VIEW.sortBy);
const [sortDir, setSortDir] = useState<'asc' | 'desc'>(DEFAULT_TASKS_VIEW.sortDir);
const [highlightTaskId, setHighlightTaskId] = useState<string | null>(
@@ -108,8 +115,10 @@ export function TasksPage() {
if (importantOnly) params.pinImportant = true;
if (assignedToMe) params.assignedToMe = true;
if (overdueOnly) params.overdue = true;
if (unassignedOnly) params.unassignedOnly = true;
if (prosthesisTypeCode) params.prosthesisTypeCode = prosthesisTypeCode;
return params;
}, [page, search, clinicId, statusFilter, stepCompleted, importantOnly, assignedToMe, overdueOnly, sortBy, sortDir]);
}, [page, search, clinicId, statusFilter, stepCompleted, importantOnly, assignedToMe, overdueOnly, unassignedOnly, prosthesisTypeCode, sortBy, sortDir]);
const displayModel = useMemo(() => groupTasksForDisplay(tasks, sortBy), [tasks, sortBy]);
@@ -126,6 +135,8 @@ export function TasksPage() {
importantOnly,
assignedToMe,
overdueOnly,
unassignedOnly,
prosthesisTypeCode,
page,
highlightTaskId,
}),
@@ -139,6 +150,8 @@ export function TasksPage() {
importantOnly,
assignedToMe,
overdueOnly,
unassignedOnly,
prosthesisTypeCode,
page,
highlightTaskId,
],
@@ -146,6 +159,18 @@ export function TasksPage() {
const showReset = !isDefaultTasksView(viewState);
useEffect(() => {
const fromUrl = parseTasksSearchParams(searchParams);
if (fromUrl.importantOnly !== undefined) setImportantOnly(fromUrl.importantOnly);
if (fromUrl.overdueOnly !== undefined) setOverdueOnly(fromUrl.overdueOnly);
if (fromUrl.unassignedOnly !== undefined) setUnassignedOnly(fromUrl.unassignedOnly);
if (fromUrl.statusFilter !== undefined) setStatusFilter(fromUrl.statusFilter);
if (fromUrl.prosthesisTypeCode !== undefined) setProsthesisTypeCode(fromUrl.prosthesisTypeCode);
if (fromUrl.sortBy !== undefined) setSortBy(fromUrl.sortBy);
if (fromUrl.sortDir !== undefined) setSortDir(fromUrl.sortDir);
setPage(1);
}, [searchParams]);
const loadTasks = useCallback(async () => {
setLoading(true);
setError('');
@@ -205,6 +230,8 @@ export function TasksPage() {
setImportantOnly(DEFAULT_TASKS_VIEW.importantOnly);
setAssignedToMe(DEFAULT_TASKS_VIEW.assignedToMe);
setOverdueOnly(DEFAULT_TASKS_VIEW.overdueOnly);
setUnassignedOnly(DEFAULT_TASKS_VIEW.unassignedOnly);
setProsthesisTypeCode(DEFAULT_TASKS_VIEW.prosthesisTypeCode);
setSortBy(DEFAULT_TASKS_VIEW.sortBy);
setSortDir(DEFAULT_TASKS_VIEW.sortDir);
setPage(DEFAULT_TASKS_VIEW.page);
@@ -223,6 +250,8 @@ export function TasksPage() {
setImportantOnly(DEFAULT_TASKS_VIEW.importantOnly);
setAssignedToMe(DEFAULT_TASKS_VIEW.assignedToMe);
setOverdueOnly(DEFAULT_TASKS_VIEW.overdueOnly);
setUnassignedOnly(DEFAULT_TASKS_VIEW.unassignedOnly);
setProsthesisTypeCode(DEFAULT_TASKS_VIEW.prosthesisTypeCode);
setSortBy(DEFAULT_TASKS_VIEW.sortBy);
setSortDir(DEFAULT_TASKS_VIEW.sortDir);
setExpandedCommentsTaskId(null);
@@ -462,6 +491,12 @@ export function TasksPage() {
label={t('overdueOnly')}
className="text-xs [&_span:last-child]:text-xs"
/>
<Checkbox
checked={unassignedOnly}
onChange={(checked) => applyFilterChange(() => setUnassignedOnly(checked))}
label={t('unassignedOnly')}
className="text-xs [&_span:last-child]:text-xs"
/>
{showReset ? (
<Button type="button" variant="ghost" size="sm" onClick={resetView}>
{t('resetView')}