Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion components/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ const Header = (props: Props): JSX.Element => {
)

if (user) {
const avatarInitial =
user.name?.charAt(0) ||
user.displayName?.charAt(0) ||
user.email?.charAt(0) ||
'?'

return (
<>
<Grid.Container justify='space-between' alignItems='center'>
Expand All @@ -83,7 +89,7 @@ const Header = (props: Props): JSX.Element => {
<Popover content={popoverContent as any} placement='bottomEnd'>
<Avatar
src={user.photoUrl || '/images/favicon-32x32.png'}
text={user?.displayName?.charAt(0)}
text={avatarInitial}
style={{ cursor: 'pointer' }}
scale={2}
/>
Expand Down
63 changes: 51 additions & 12 deletions lib/admin-db/infusions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { adminFirestore } from 'lib/firebase-admin'
import { compareDesc, parseISO } from 'date-fns'

import type { TreatmentType } from '../db/infusions'
import {
TreatmentTypeEnum,
type TreatmentType,
} from '../db/infusions'
import type { AttachedUserType } from 'lib/types/users'

async function getAllInfusions() {
const snapshot = await adminFirestore.collection('infusions').get()
Expand Down Expand Up @@ -118,7 +122,7 @@ async function getRecentUserInfusionsByApiKey(

async function postInfusionByApiKey(
apiKey: string,
lastInfusion: TreatmentType,
lastInfusion: TreatmentType | null,
newInfusion: Partial<TreatmentType>
) {
try {
Expand All @@ -134,19 +138,54 @@ async function postInfusionByApiKey(
)
}

// Make room for new values
Object.assign(lastInfusion, {
createdAt: new Date().toISOString(),
cause: '',
sites: '',
})
const userDoc = userSnapshot.docs[0]
const baseUser: AttachedUserType = {
email: userDoc.data().email || '',
name: userDoc.data().name || userDoc.data().displayName || '',
photoUrl: userDoc.data().photoUrl || '',
uid: userDoc.data().uid || userDoc.id,
}

const now = new Date().toISOString()
const baseInfusion: TreatmentType = lastInfusion
? { ...lastInfusion }
: {
cause: '',
createdAt: now,
date: newInfusion.date || now.slice(0, 10),
deletedAt: null,
medication: {
brand: newInfusion.medication?.brand || '',
costPerUnit: newInfusion.medication?.costPerUnit,
lot: newInfusion.medication?.lot,
units: newInfusion.medication?.units || 0,
},
sites: '',
type: newInfusion.type || TreatmentTypeEnum.PROPHY,
user: (newInfusion.user as AttachedUserType) || baseUser,
}

const sanitizedBase = {
...baseInfusion,
createdAt: now,
cause: baseInfusion.cause || '',
sites: baseInfusion.sites || '',
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: New treatments inherit cause and sites from previous treatment

The refactored code preserves cause and sites values from lastInfusion when they're non-empty, whereas the original code always reset them to empty strings. When a user logs a new treatment via API, the cause and sites fields from their previous treatment will now carry over unless explicitly overridden by newInfusion. Each treatment event has its own cause and injection sites, so inheriting these from a previous treatment produces incorrect data. The baseInfusion.cause || '' pattern keeps existing values, but the old Object.assign with cause: '' always cleared them.

Fix in Cursor Fix in Web

deletedAt: null,
user: baseInfusion.user || baseUser,
}

delete lastInfusion.uid
delete (sanitizedBase as Partial<TreatmentType>).uid

// Keep data from last infusion and replace old with new data
const infusion = {
...lastInfusion,
const infusion: TreatmentType = {
...sanitizedBase,
...newInfusion,
user: (newInfusion.user as AttachedUserType) || sanitizedBase.user,
medication: {
...sanitizedBase.medication,
...(newInfusion.medication || {}),
},
createdAt: now,
deletedAt: null,
}

await adminFirestore
Expand Down
4 changes: 2 additions & 2 deletions lib/db/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ async function createUser(uid: string, data: any) {
}

async function deleteUser(uid: string) {
firestore.collection('users').doc(uid).delete()
await firestore.collection('users').doc(uid).delete()
const snapshot = await firestore
.collection('infusions')
.where('userId', '==', uid)
.where('user.uid', '==', uid)
.get()

const batch = firestore.batch()
Expand Down
2 changes: 1 addition & 1 deletion pages/api/log-treatment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const logTreatment = async (req: NextApiRequest, res: NextApiResponse) => {

if (error) throw error

const mostRecentInfusion = infusions[0]
const mostRecentInfusion = infusions && infusions.length > 0 ? infusions[0] : null
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Sparse array causes incorrect null check for infusions

The check infusions.length > 0 doesn't correctly detect when there are no infusions. The upstream getRecentUserInfusionsByApiKey function sets infusions.length = 3 unconditionally, creating a sparse array even when no infusions exist. This means infusions.length > 0 is always true, and infusions[0] returns undefined (not null) when the user has no infusions. The parameter type expects TreatmentType | null, but undefined gets passed instead, which could cause type errors in strict mode and doesn't match the intended behavior.

Fix in Cursor Fix in Web


try {
const { infusion, error } = await postInfusionByApiKey(
Expand Down
Loading