mirror of
https://github.com/Tony0410/nextstep.git
synced 2026-05-24 21:31:43 +08:00
Add 11 major features for caregiver health management
Features added: - Emergency Info Card: Full-screen emergency view with patient info - Refill Tracker: Track pill counts with auto-decrement on dose - Activity Feed: View caregiver activity with filtering - Symptom Tracker: Log symptoms with severity and offline sync - Print Views: Daily meds, appointments, doctor visit summaries - iCal Export: Calendar subscription for appointments - PDF Export: Medical summary for doctor visits - Calendar View: Monthly calendar for appointments - Appointment Preparation: Checklist for upcoming appointments - Medication Reminders: PWA push notifications with quiet hours Bug fixes: - Fix invite workflow: Register/login now properly redirect back - Add undo for doctor questions (can unmark "asked" questions) - Fix API route type annotations for Next.js 14 compatibility - Add Suspense boundary for useSearchParams in login/register Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@ import { useEffect, useState, useCallback } from 'react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { format, isToday, isTomorrow } from 'date-fns'
|
||||
import { toZonedTime } from 'date-fns-tz'
|
||||
import { Phone, MapPin, Clock, ChevronRight, Pill, Calendar, Plus } from 'lucide-react'
|
||||
import { Phone, MapPin, Clock, ChevronRight, Pill, Calendar, Plus, AlertTriangle, ClipboardCheck } from 'lucide-react'
|
||||
import { useLiveQuery } from 'dexie-react-hooks'
|
||||
|
||||
import { db, logDose, undoDose } from '@/lib/sync'
|
||||
@@ -12,6 +12,7 @@ import { calculateAllMedicationsDue, formatTimeUntil } from '@/lib/schedule'
|
||||
import type { Medication, DoseLog, MedicationDueStatus } from '@/lib/schedule'
|
||||
import { Card, CardTitle, Button, LoadingState, EmptyState, showUndoToast, showToast } from '@/components/ui'
|
||||
import { Header, PageContainer } from '@/components/layout/header'
|
||||
import { RefillAlert } from '@/components/medications/RefillAlert'
|
||||
import { useApp } from '../provider'
|
||||
|
||||
const TIMEZONE = 'Australia/Perth'
|
||||
@@ -173,21 +174,38 @@ export default function TodayPage() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Call Clinic Button */}
|
||||
{currentWorkspace.clinicPhone && (
|
||||
<a
|
||||
href={`tel:${currentWorkspace.clinicPhone}`}
|
||||
className="flex items-center gap-3 p-4 bg-primary-50 rounded-card border border-primary-100 hover:bg-primary-100 transition-colors"
|
||||
{/* Emergency & Call Clinic Buttons */}
|
||||
<div className="flex gap-3">
|
||||
{/* Emergency Info Button */}
|
||||
<button
|
||||
onClick={() => router.push('/emergency')}
|
||||
className="flex items-center gap-3 p-4 bg-red-50 rounded-card border border-red-200 hover:bg-red-100 transition-colors flex-1"
|
||||
>
|
||||
<div className="w-10 h-10 rounded-full bg-primary-500 flex items-center justify-center">
|
||||
<Phone className="w-5 h-5 text-white" />
|
||||
<div className="w-10 h-10 rounded-full bg-red-600 flex items-center justify-center">
|
||||
<AlertTriangle className="w-5 h-5 text-white" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-medium text-primary-800">Call Clinic</p>
|
||||
<p className="text-sm text-primary-600">{currentWorkspace.clinicPhone}</p>
|
||||
<div className="text-left">
|
||||
<p className="font-medium text-red-800">Emergency</p>
|
||||
<p className="text-sm text-red-600">Medical info</p>
|
||||
</div>
|
||||
</a>
|
||||
)}
|
||||
</button>
|
||||
|
||||
{/* Call Clinic Button */}
|
||||
{currentWorkspace.clinicPhone && (
|
||||
<a
|
||||
href={`tel:${currentWorkspace.clinicPhone}`}
|
||||
className="flex items-center gap-3 p-4 bg-primary-50 rounded-card border border-primary-100 hover:bg-primary-100 transition-colors flex-1"
|
||||
>
|
||||
<div className="w-10 h-10 rounded-full bg-primary-500 flex items-center justify-center">
|
||||
<Phone className="w-5 h-5 text-white" />
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<p className="font-medium text-primary-800">Call Clinic</p>
|
||||
<p className="text-sm text-primary-600 truncate">{currentWorkspace.clinicPhone}</p>
|
||||
</div>
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Next Appointment */}
|
||||
<section>
|
||||
@@ -258,6 +276,51 @@ export default function TodayPage() {
|
||||
)}
|
||||
</section>
|
||||
|
||||
{/* Prep Reminder for Tomorrow's Appointment */}
|
||||
{appointments && appointments.length > 0 && (() => {
|
||||
const tomorrowAppt = appointments.find((appt) =>
|
||||
isTomorrow(toZonedTime(new Date(appt.datetime), TIMEZONE))
|
||||
)
|
||||
if (tomorrowAppt) {
|
||||
return (
|
||||
<section>
|
||||
<Card
|
||||
className="bg-green-50 border border-green-200 cursor-pointer hover:bg-green-100 transition-colors"
|
||||
onClick={() => router.push(`/appointments/${tomorrowAppt.id}/prep`)}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-full bg-green-500 flex items-center justify-center flex-shrink-0">
|
||||
<ClipboardCheck className="w-5 h-5 text-white" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<p className="font-medium text-green-800">
|
||||
Prepare for tomorrow
|
||||
</p>
|
||||
<p className="text-sm text-green-600">
|
||||
{tomorrowAppt.title} at {format(toZonedTime(new Date(tomorrowAppt.datetime), TIMEZONE), 'h:mm a')}
|
||||
</p>
|
||||
</div>
|
||||
<ChevronRight className="w-5 h-5 text-green-500" />
|
||||
</div>
|
||||
</Card>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
return null
|
||||
})()}
|
||||
|
||||
{/* Refill Alerts */}
|
||||
{medications && medications.length > 0 && (
|
||||
<RefillAlert
|
||||
medications={medications.map(m => ({
|
||||
id: m.id,
|
||||
name: m.name,
|
||||
pillCount: m.pillCount,
|
||||
refillThreshold: m.refillThreshold,
|
||||
}))}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Meds Due */}
|
||||
<section>
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
|
||||
Reference in New Issue
Block a user