From 94fe3adf04565119087a7908717103c7ede7423a Mon Sep 17 00:00:00 2001 From: onohesey Date: Mon, 1 Jun 2026 19:27:06 +0900 Subject: [PATCH 1/3] =?UTF-8?q?fix(medical):=20api=20=ED=98=B8=EC=B6=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/app/api/medical.ts | 10 ++++++++-- .../src/app/components/HealthLogScreen.tsx | 3 ++- .../app/components/MedicalRecordsScreen.tsx | 1 + .../app/components/MedicalUploadScreen.tsx | 20 +++++++++++-------- .../src/app/components/OnboardingStep3.tsx | 5 +++++ 5 files changed, 28 insertions(+), 11 deletions(-) diff --git a/frontend/src/app/api/medical.ts b/frontend/src/app/api/medical.ts index 640a1de..fb1d2e2 100644 --- a/frontend/src/app/api/medical.ts +++ b/frontend/src/app/api/medical.ts @@ -158,14 +158,19 @@ export async function analyzeMedicalOcr( return parseEnvelope(res); } -export async function uploadMedicalRecord(body: MedicalUploadBody): Promise { +export async function uploadMedicalRecord(body: MedicalUploadBody): Promise { const petId = Number(getPetId()); const res = await safeFetch(`${API_BASE}/api/upload/medical`, { method: 'POST', headers: { 'Content-Type': 'application/json', ...authHeaders() }, body: JSON.stringify({ ...body, petId }), }); - return parseEnvelope(res); + if (!res.ok) return parseEnvelope(res); + try { + return await parseEnvelope(res); + } catch { + return null; + } } export async function getLatestMedicalSummary(): Promise { @@ -174,3 +179,4 @@ export async function getLatestMedicalSummary(): Promise { }); return parseEnvelope(res); } + diff --git a/frontend/src/app/components/HealthLogScreen.tsx b/frontend/src/app/components/HealthLogScreen.tsx index b6a741f..757b7af 100644 --- a/frontend/src/app/components/HealthLogScreen.tsx +++ b/frontend/src/app/components/HealthLogScreen.tsx @@ -71,7 +71,7 @@ const symptomChips = [ { id: 'itch', label: '가렀움', emoji: '🐾' }, { id: 'appetite', label: 'μ‹μš•λΆ€μ§„', emoji: '🍽️' }, { id: 'lethargy', label: 'κΈ°λ ₯μ €ν•˜', emoji: '😴' }, - { id: 'limp', label: 'θ·›θ‘Œ', emoji: '🦡' }, + { id: 'limp', label: 'νŒŒν–‰', emoji: '🦡' }, { id: 'eye', label: '눈 λΆ„λΉ„λ¬Ό', emoji: 'πŸ‘οΈ' }, { id: 'ear', label: 'κ·€ 긁음', emoji: 'πŸ‘‚' }, ]; @@ -601,3 +601,4 @@ export default function HealthLogScreen() { ); } + diff --git a/frontend/src/app/components/MedicalRecordsScreen.tsx b/frontend/src/app/components/MedicalRecordsScreen.tsx index 9c9df0c..e2c54a5 100644 --- a/frontend/src/app/components/MedicalRecordsScreen.tsx +++ b/frontend/src/app/components/MedicalRecordsScreen.tsx @@ -238,6 +238,7 @@ export default function MedicalRecordsScreen() {

처방 내역이 μ—†μ–΄μš”

)} + )} diff --git a/frontend/src/app/components/MedicalUploadScreen.tsx b/frontend/src/app/components/MedicalUploadScreen.tsx index 0633ddf..b519429 100644 --- a/frontend/src/app/components/MedicalUploadScreen.tsx +++ b/frontend/src/app/components/MedicalUploadScreen.tsx @@ -45,6 +45,10 @@ export default function MedicalUploadScreen() { const [analyzeStep, setAnalyzeStep] = useState(0); const [ocrData, setOcrData] = useState({ hospital: '', date: '', items: '', diagnosis: '', amount: '' }); const [showTypePicker, setShowTypePicker] = useState(false); +<<<<<<< Updated upstream +======= + const [ocrImageUrls, setOcrImageUrls] = useState([]); +>>>>>>> Stashed changes const [ocrError, setOcrError] = useState(null); const [saving, setSaving] = useState(false); const [saveError, setSaveError] = useState(null); @@ -80,13 +84,6 @@ export default function MedicalUploadScreen() { }); }; - const readAsDataUrl = (file: File): Promise => new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.onload = () => resolve(String(reader.result ?? '')); - reader.onerror = () => reject(new Error('Failed to read file')); - reader.readAsDataURL(file); - }); - const handleAnalyze = async () => { setScreenState('analyzing'); setAnalyzeStep(0); @@ -103,7 +100,8 @@ export default function MedicalUploadScreen() { clearInterval(interval); - const { extracted } = result; + const { extracted, imageUrls } = result; + setOcrImageUrls(imageUrls ?? []); setOcrData({ hospital: extracted.clinicName ?? '', date: extracted.visitDate || selectedDate, @@ -113,6 +111,7 @@ export default function MedicalUploadScreen() { }); } catch (e) { clearInterval(interval); + setOcrImageUrls([]); setOcrData({ hospital: '', date: selectedDate, items: '', diagnosis: '', amount: '' }); setOcrError(e instanceof Error ? e.message : 'OCR 뢄석에 μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€. 직접 μž…λ ₯ν•΄μ£Όμ„Έμš”.'); } @@ -137,7 +136,11 @@ export default function MedicalUploadScreen() { content: ocrData.items, diagnosis: ocrData.diagnosis, totalCost: ocrData.amount, +<<<<<<< Updated upstream image: imageBase64, +======= + image: ocrImageUrls, +>>>>>>> Stashed changes }); navigate('/medical-records', { replace: true }); } catch (e) { @@ -417,3 +420,4 @@ export default function MedicalUploadScreen() { ); } + diff --git a/frontend/src/app/components/OnboardingStep3.tsx b/frontend/src/app/components/OnboardingStep3.tsx index b900050..c61d1d6 100644 --- a/frontend/src/app/components/OnboardingStep3.tsx +++ b/frontend/src/app/components/OnboardingStep3.tsx @@ -259,12 +259,16 @@ export default function OnboardingStep3() { setSaving(true); setSaveError(''); try { +<<<<<<< Updated upstream let profileImageUrl: string | undefined; if (step1.photoFile) { profileImageUrl = await uploadProfileImage(step1.photoFile); } await createPet({ +======= + const pet = await createPet({ +>>>>>>> Stashed changes type: step1.petType ?? 'DOG', name: step1.name, breed: step1.breed, @@ -280,6 +284,7 @@ export default function OnboardingStep3() { isCompleted, })), }); + localStorage.setItem('hyfive_petId', String(pet.petId)); setConfirmed(true); navigate('/home'); } catch (e) { From ccc14832de8070f3e690a7e81b22f4d78ec65174 Mon Sep 17 00:00:00 2001 From: onohesey Date: Mon, 1 Jun 2026 19:57:02 +0900 Subject: [PATCH 2/3] =?UTF-8?q?fix(medical):=20conflict=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/app/components/MedicalUploadScreen.tsx | 12 ------------ frontend/src/app/components/OnboardingStep3.tsx | 4 ---- 2 files changed, 16 deletions(-) diff --git a/frontend/src/app/components/MedicalUploadScreen.tsx b/frontend/src/app/components/MedicalUploadScreen.tsx index b519429..bd9fa9d 100644 --- a/frontend/src/app/components/MedicalUploadScreen.tsx +++ b/frontend/src/app/components/MedicalUploadScreen.tsx @@ -45,10 +45,7 @@ export default function MedicalUploadScreen() { const [analyzeStep, setAnalyzeStep] = useState(0); const [ocrData, setOcrData] = useState({ hospital: '', date: '', items: '', diagnosis: '', amount: '' }); const [showTypePicker, setShowTypePicker] = useState(false); -<<<<<<< Updated upstream -======= const [ocrImageUrls, setOcrImageUrls] = useState([]); ->>>>>>> Stashed changes const [ocrError, setOcrError] = useState(null); const [saving, setSaving] = useState(false); const [saveError, setSaveError] = useState(null); @@ -124,11 +121,6 @@ export default function MedicalUploadScreen() { setSaving(true); setSaveError(null); try { - const base64List = await Promise.all(receiptFiles.map(readAsDataUrl)); - const imageBase64 = base64List.map(b => { - const idx = b.indexOf(','); - return idx >= 0 ? b.substring(idx + 1) : b; - }); await uploadMedicalRecord({ type: TYPE_MAP[medType], clinicName: ocrData.hospital, @@ -136,11 +128,7 @@ export default function MedicalUploadScreen() { content: ocrData.items, diagnosis: ocrData.diagnosis, totalCost: ocrData.amount, -<<<<<<< Updated upstream - image: imageBase64, -======= image: ocrImageUrls, ->>>>>>> Stashed changes }); navigate('/medical-records', { replace: true }); } catch (e) { diff --git a/frontend/src/app/components/OnboardingStep3.tsx b/frontend/src/app/components/OnboardingStep3.tsx index c61d1d6..44839a5 100644 --- a/frontend/src/app/components/OnboardingStep3.tsx +++ b/frontend/src/app/components/OnboardingStep3.tsx @@ -259,16 +259,12 @@ export default function OnboardingStep3() { setSaving(true); setSaveError(''); try { -<<<<<<< Updated upstream let profileImageUrl: string | undefined; if (step1.photoFile) { profileImageUrl = await uploadProfileImage(step1.photoFile); } - await createPet({ -======= const pet = await createPet({ ->>>>>>> Stashed changes type: step1.petType ?? 'DOG', name: step1.name, breed: step1.breed, From d4f7a401f91c6338b93182af809df8a4c7851efe Mon Sep 17 00:00:00 2001 From: onohesey Date: Mon, 1 Jun 2026 20:26:22 +0900 Subject: [PATCH 3/3] =?UTF-8?q?fix(medical):=20typescript=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/app/components/OnboardingStep3.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/src/app/components/OnboardingStep3.tsx b/frontend/src/app/components/OnboardingStep3.tsx index 4edb709..eefb563 100644 --- a/frontend/src/app/components/OnboardingStep3.tsx +++ b/frontend/src/app/components/OnboardingStep3.tsx @@ -264,7 +264,6 @@ export default function OnboardingStep3() { profileImageUrl = await uploadProfileImage(step1.photoFile); } - const pet = await createPet({ const createdPet = await createPet({ type: step1.petType ?? 'DOG', name: step1.name, @@ -281,7 +280,6 @@ export default function OnboardingStep3() { isCompleted, })), }); - localStorage.setItem('hyfive_petId', String(pet.petId)); localStorage.setItem('hyfive_petId', String(createdPet.petId)); setConfirmed(true); navigate('/home');