mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-04-11 18:28:15 +00:00
feat: add Patient 360 page and global search component
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,24 @@
|
|||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router';
|
import { useNavigate } from 'react-router';
|
||||||
import { SearchLg, User01, Phone01, Calendar } from '@untitledui/icons';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import { faMagnifyingGlass, faUser, faCalendar } from '@fortawesome/pro-duotone-svg-icons';
|
||||||
|
import type { FC, HTMLAttributes } from 'react';
|
||||||
import { Input } from '@/components/base/input/input';
|
import { Input } from '@/components/base/input/input';
|
||||||
import { Badge } from '@/components/base/badges/badges';
|
import { Badge } from '@/components/base/badges/badges';
|
||||||
import { useData } from '@/providers/data-provider';
|
import { useData } from '@/providers/data-provider';
|
||||||
import { formatPhone } from '@/lib/format';
|
import { formatPhone } from '@/lib/format';
|
||||||
import { cx } from '@/utils/cx';
|
import { cx } from '@/utils/cx';
|
||||||
|
|
||||||
|
const SearchIcon: FC<HTMLAttributes<HTMLOrSVGElement>> = ({ className }) => (
|
||||||
|
<FontAwesomeIcon icon={faMagnifyingGlass} className={className} />
|
||||||
|
);
|
||||||
|
const UserIcon: FC<HTMLAttributes<HTMLOrSVGElement>> = ({ className }) => (
|
||||||
|
<FontAwesomeIcon icon={faUser} className={className} />
|
||||||
|
);
|
||||||
|
const CalendarIcon: FC<HTMLAttributes<HTMLOrSVGElement>> = ({ className }) => (
|
||||||
|
<FontAwesomeIcon icon={faCalendar} className={className} />
|
||||||
|
);
|
||||||
|
|
||||||
type SearchResultType = 'lead' | 'patient' | 'appointment';
|
type SearchResultType = 'lead' | 'patient' | 'appointment';
|
||||||
|
|
||||||
type SearchResult = {
|
type SearchResult = {
|
||||||
@@ -21,10 +33,10 @@ type GlobalSearchProps = {
|
|||||||
onSelectResult?: (result: SearchResult) => void;
|
onSelectResult?: (result: SearchResult) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const TYPE_ICONS: Record<SearchResultType, typeof User01> = {
|
const TYPE_ICONS: Record<SearchResultType, FC<{ className?: string }>> = {
|
||||||
lead: User01,
|
lead: UserIcon,
|
||||||
patient: User01,
|
patient: UserIcon,
|
||||||
appointment: Calendar,
|
appointment: CalendarIcon,
|
||||||
};
|
};
|
||||||
|
|
||||||
const TYPE_BADGE_COLORS: Record<SearchResultType, 'brand' | 'success' | 'blue'> = {
|
const TYPE_BADGE_COLORS: Record<SearchResultType, 'brand' | 'success' | 'blue'> = {
|
||||||
@@ -170,7 +182,7 @@ export const GlobalSearch = ({ onSelectResult }: GlobalSearchProps) => {
|
|||||||
<div ref={containerRef} className="relative w-64" onKeyDown={handleKeyDown}>
|
<div ref={containerRef} className="relative w-64" onKeyDown={handleKeyDown}>
|
||||||
<Input
|
<Input
|
||||||
placeholder="Search leads..."
|
placeholder="Search leads..."
|
||||||
icon={SearchLg}
|
icon={SearchIcon}
|
||||||
aria-label="Global search"
|
aria-label="Global search"
|
||||||
value={query}
|
value={query}
|
||||||
onChange={(value) => setQuery(value)}
|
onChange={(value) => setQuery(value)}
|
||||||
@@ -213,7 +225,7 @@ export const GlobalSearch = ({ onSelectResult }: GlobalSearchProps) => {
|
|||||||
|
|
||||||
{!isSearching && results.length === 0 && (
|
{!isSearching && results.length === 0 && (
|
||||||
<div className="flex flex-col items-center gap-1 px-4 py-6 text-center">
|
<div className="flex flex-col items-center gap-1 px-4 py-6 text-center">
|
||||||
<SearchLg className="size-5 text-fg-quaternary" />
|
<SearchIcon className="size-5 text-fg-quaternary" />
|
||||||
<p className="text-sm font-medium text-secondary">No results</p>
|
<p className="text-sm font-medium text-secondary">No results</p>
|
||||||
<p className="text-xs text-tertiary">Try a different search term</p>
|
<p className="text-xs text-tertiary">Try a different search term</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useMemo, useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
import { useParams } from 'react-router';
|
import { useParams } from 'react-router';
|
||||||
import { Phone01, Mail01, Calendar, FileText06, Clock, MessageTextSquare01, Plus } from '@untitledui/icons';
|
import { Phone01, Mail01, Calendar, MessageTextSquare01, Plus } from '@untitledui/icons';
|
||||||
import { Tabs, TabList, Tab, TabPanel } from '@/components/application/tabs/tabs';
|
import { Tabs, TabList, Tab, TabPanel } from '@/components/application/tabs/tabs';
|
||||||
import { TopBar } from '@/components/layout/top-bar';
|
import { TopBar } from '@/components/layout/top-bar';
|
||||||
import { Avatar } from '@/components/base/avatar/avatar';
|
import { Avatar } from '@/components/base/avatar/avatar';
|
||||||
|
|||||||
Reference in New Issue
Block a user