diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index c62967db..bbc6bde4 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -53,6 +53,9 @@ Remember: Clear writing is clear thinking. If you can't write it simply, you don - Always write commits in English. - Follow the conventional commit standard for all commits: eg: `feat(scope): message` -- Always specify the commit type and write the corresponding commit message -- Detect the appropriate commit type and write the corresponding commit message -- Try to summarize the commit message in a single line +- Always check `git status` before committing to review staged files +- Create a main resume line highlighting the **most impactful change**, not implementation details +- Add a detailed description after a blank line with bullet points for supporting changes +- List secondary changes as bullet points, ordered by importance +- If multiple files are changed, only commit the files you explicitly staged (never include unrelated changes) +- Apply the Zinsser brevity principles: remove unnecessary words, use active voice, and write clearly diff --git a/src/app/(dashboard)/_cards/patients-by-city.tsx b/src/app/(dashboard)/_cards/patients-by-city.tsx index a98c4a6b..aec84449 100644 --- a/src/app/(dashboard)/_cards/patients-by-city.tsx +++ b/src/app/(dashboard)/_cards/patients-by-city.tsx @@ -67,7 +67,7 @@ export function DashboardOverviewPatientsByCity( {isLoading && } {!isLoading && !isEmpty && ( -
+
Dados Gerais

+ return ( +
+ + + + + + +
+ ) } diff --git a/src/components/ui/tab-select.tsx b/src/components/ui/tab-select.tsx index fa23d0bd..29513c94 100644 --- a/src/components/ui/tab-select.tsx +++ b/src/components/ui/tab-select.tsx @@ -20,7 +20,7 @@ export function TabSelect({ }: Readonly) { return (
{buttons.map(({ label, isActive, className, ...buttonProps }) => ( @@ -29,7 +29,7 @@ export function TabSelect({ variant='ghost' data-active={isActive} className={cn( - 'text-disabled hover:bg-background hover:text-foreground h-auto min-h-auto rounded-md text-sm hover:shadow', + 'text-foreground-soft hover:bg-background hover:text-foreground h-auto min-h-auto flex-1 rounded-md hover:shadow', 'data-[active=true]:bg-background data-[active=true]:text-foreground data-[active=true]:pointer-events-none data-[active=true]:shadow', className, )} diff --git a/src/modules/referrals/by-category-card.tsx b/src/modules/referrals/by-category-card.tsx new file mode 100644 index 00000000..20372b2b --- /dev/null +++ b/src/modules/referrals/by-category-card.tsx @@ -0,0 +1,47 @@ +'use client' + +import { ChartBarDecreasingIcon } from 'lucide-react' + +import { BarChart } from '@/components/charts/bar' +import { DashboardCardChart } from '@/components/dashboard/cards/chart' + +const MOCK_DATA = [ + { label: 'Advogado', value: 15 }, + { label: 'Enfermeiro', value: 30 }, + { label: 'Fisioterapeuta', value: 22 }, + { label: 'Médico', value: 45 }, + { label: 'Neurologista', value: 15 }, + { label: 'Nutricionista', value: 18 }, + { label: 'Oftalmologista', value: 11 }, + { label: 'Psicólogo', value: 35 }, + { label: 'Psiquiatra', value: 55 }, + { label: 'Serviço social', value: 8 }, +] + +const isEmpty = MOCK_DATA.length === 0 + +export function ReferralsByCategoryCard( + props: Readonly>, +) { + return ( + +
+ {!isEmpty && ( +
+ +
+ )} + + {isEmpty && ( +

+ Nenhum encaminhamento por especialista registrado. +

+ )} +
+
+ ) +} diff --git a/src/modules/referrals/by-city-cards.tsx b/src/modules/referrals/by-city-cards.tsx new file mode 100644 index 00000000..de4cee99 --- /dev/null +++ b/src/modules/referrals/by-city-cards.tsx @@ -0,0 +1,75 @@ +'use client' + +import { ChartPieIcon } from 'lucide-react' + +import { PieChart } from '@/components/charts/pie' +import { DashboardCardChart } from '@/components/dashboard/cards/chart' + +const PIE_COLORS = [ + '#E255F2', + '#DF1C41', + '#0F37E0', + '#008B62', + '#F17B2C', + '#F2AE40', + '#3AB795', + '#8C6DFD', +] + +const MOCK_DATA = { + cities: [ + { city: 'São Paulo', percentage: 45 }, + { city: 'Rio de Janeiro', percentage: 25 }, + { city: 'São José do Rio Preto', percentage: 15 }, + { city: 'Salvador', percentage: 8 }, + { city: 'Fortaleza', percentage: 5 }, + { city: 'Curitiba', percentage: 5 }, + { city: 'Recife', percentage: 34 }, + { city: 'Porto Alegre', percentage: 18 }, + ], +} + +const data = MOCK_DATA.cities.map((item, index) => ({ + label: item.city, + value: item.percentage, + color: PIE_COLORS[index], +})) + +export function ReferralsByCityCards( + props: Readonly>, +) { + return ( + +
+ + +
+ {data.map((city) => { + return ( +
+
+ {city.label} + {city.value}% +
+ ) + })} +
+
+ + ) +} diff --git a/src/modules/referrals/period-tab.tsx b/src/modules/referrals/period-tab.tsx new file mode 100644 index 00000000..bd6ef2cb --- /dev/null +++ b/src/modules/referrals/period-tab.tsx @@ -0,0 +1,42 @@ +'use client' + +import { TabSelect } from '@/components/ui/tab-select' +import { usePeriodStore } from '@/store/period' + +export function ReferralsPeriodTab() { + const { period, setPeriod } = usePeriodStore() + + const filterOptions = [ + { + label: 'Hoje', + value: 'today', + isActive: period === 'today', + }, + { + label: 'Na última semana', + value: 'last_week', + isActive: period === 'last_week', + }, + { + label: 'No último mês', + value: 'last_month', + isActive: period === 'last_month', + }, + { + label: 'No último ano', + value: 'last_year', + isActive: period === 'last_year', + }, + ] as const + + return ( + ({ + label: option.label, + isActive: option.value === period, + onClick: () => setPeriod(option.value), + }))} + className='col-span-full' + /> + ) +} diff --git a/src/modules/referrals/summary-card.tsx b/src/modules/referrals/summary-card.tsx new file mode 100644 index 00000000..d177a1fc --- /dev/null +++ b/src/modules/referrals/summary-card.tsx @@ -0,0 +1,62 @@ +import { HeartPulse, Waypoints } from 'lucide-react' + +import { + getMockReferralsCount, + getMockReferredPatients, +} from '@/app/(dashboard)/encaminhados/_cards/mock-data' +import { Card } from '@/components/ui/card' + +export function ReferralsSummaryCard() { + const referrals = getMockReferralsCount() + const referredPatients = getMockReferredPatients() + + const statistics = [ + { + value: referrals.total, + label: 'referrals', + }, + { + value: `${referredPatients.percentage}%`, + label: 'patients', + }, + ] as const + + const STATISTICS_MAPPING = { + referrals: { + title: ( + <> + Total de encaminhamentos + + ), + icon: Waypoints, + }, + patients: { + title: ( + <> + Total de pacientes com encaminhamento + + ), + icon: HeartPulse, + }, + } as const + + return statistics.map((statistic) => { + const data = STATISTICS_MAPPING[statistic.label] + const Icon = data.icon + + return ( + +
+ {statistic.value} +
+ +
+
+

{data.title}

+
+ ) + }) +} diff --git a/src/store/period.ts b/src/store/period.ts new file mode 100644 index 00000000..6d428dfa --- /dev/null +++ b/src/store/period.ts @@ -0,0 +1,13 @@ +import { create } from 'zustand' + +export type Period = 'today' | 'last_week' | 'last_month' | 'last_year' + +interface PeriodState { + period: Period + setPeriod: (period: Period) => void +} + +export const usePeriodStore = create((set) => ({ + period: 'today', + setPeriod: (period) => set({ period }), +}))