Skip to content

Add Pharmacy Panic — real-time medicine price comparison across Vietnam's pharmacy chains#84

Open
giaphutran12 wants to merge 18 commits intotinyfish-io:mainfrom
giaphutran12:feat-giaphutran12/pharmacy-panic
Open

Add Pharmacy Panic — real-time medicine price comparison across Vietnam's pharmacy chains#84
giaphutran12 wants to merge 18 commits intotinyfish-io:mainfrom
giaphutran12:feat-giaphutran12/pharmacy-panic

Conversation

@giaphutran12
Copy link
Copy Markdown
Contributor

Summary

  • New cookbook app: pharmacy-panic/ — real-time medicine and health product price comparison across Vietnam's 5 major pharmacy chains (Long Châu, Pharmacity, An Khang, Guardian, Medicare)
  • Parallel TinyFish SSE scraping with live browser preview iframes, VND pricing with per-unit normalization, stock status indicators, and promotional badge detection
  • Follows viet-bike-scout architecture exactly: SSE streaming API route, client consumer hook, optional Supabase caching with graceful degradation

What it does

Users search for any medicine or health product (e.g. "Paracetamol", "Vitamin C"). TinyFish browser agents scrape all 5 pharmacy chains simultaneously via SSE, streaming results back in real-time with:

  • Vietnamese product names with brand, dosage form, and quantity
  • VND prices with per-unit normalization (₫/viên, ₫/hộp)
  • Stock status (in stock / out of stock / prescription required)
  • Promo badge detection ("Giảm 11%", "Flash Sale")
  • Live browser preview iframes showing TinyFish agents at work
  • Category preset buttons for common searches

Tech Stack

Next.js 16 (App Router) · React 19 · TypeScript (strict) · Tailwind CSS 4 · shadcn/ui · Zod · Supabase (optional) · TinyFish SSE API

Key files

File Purpose
src/app/api/search/route.ts SSE endpoint — parallel pharmacy scraping via TinyFish with 15s keepalive pings
src/hooks/use-pharmacy-search.ts Client SSE consumer hook with normalization
src/lib/normalize.ts VND price parsing, dosage form mapping, stock status normalization
src/lib/env.ts Zod env validation (API key required, Supabase optional)
src/app/page.tsx Main UI — search input, preset buttons, results grid

Verification

  • npm run build
  • npm run lint ✅ (0 errors, 0 warnings)
  • npx tsc --noEmit
  • npx vitest run ✅ (54 tests pass)
  • Live QA with TinyFish API ✅ (3/5 pharmacies return products)

giaphutran12 and others added 17 commits March 5, 2026 20:17
…cout

Add Vietnam Bike Price Scout cookbook example
- Initialize pharmacy-panic/ directory at repo root
- Match exact dependency versions from viet-bike-scout (Next 16.1.6, React 19.2.3, Zod 4.3.6)
- Copy all config files: tsconfig, next.config, postcss, eslint, components.json
- Add Tailwind 4 theme with oklch variables
- Add layout with Pharmacy Panic metadata + Geist fonts
- Add placeholder page.tsx
- Add .env.example and .gitignore
… components

- Add PharmacyProduct, PharmacyResult, StreamingPreview, SearchState types
- Add VND price normalization with Vietnamese format handling
- Add dosage form, stock status, and per-unit price normalization
- Add Zod env validation (API key required, Supabase optional)
- Add Supabase client with tryGetSupabase() graceful degradation
- Install shadcn/ui: button, card, badge, skeleton components
- POST /api/search with SSE streaming response
- Parallel scraping of 5 pharmacy chains via Promise.allSettled
- GOAL_PROMPT for Vietnamese pharmacy product extraction
- Cache-aside pattern with optional Supabase (fire-and-forget writes)
- normalizePharmacyResult + isEmptyResult for anti-bot detection
- runtime=nodejs, maxDuration=800
- Add usePharmacySearch() hook with SSE stream consumption
- Handle STREAMING_URL, PHARMACY_RESULT, SEARCH_COMPLETE events
- Max 5 iframes, dedup by siteUrl, abort support
- Add LivePreviewGrid component (near-verbatim from viet-bike-scout)
- Add pharmacy-badge, product-card, pharmacy-group, savings-banner components
- Add results-grid container component
- Build main page with search input, category presets, live preview
- Preset buttons auto-search on click (Paracetamol, Vitamin C, etc.)
- Progress bar, loading skeletons, error state, empty state
- No inline styles — all Tailwind classes
- Add vitest config with path aliases
- Test normalizePrice: VND formats, null handling, edge cases
- Test normalizeDosageForm: Vietnamese to English mapping
- Test normalizeStockStatus: stock status normalization
- Test computePricePerUnit, formatVND, isEmptyResult
- Test normalizePharmacyResult: full pipeline integration
- Add README.md with all 7 CONTRIBUTING.md-required sections
- Fix unused variable lint warnings (REQUEST_STAGGER_MS, PharmacyResult import)
- Architecture diagram, API snippet, setup instructions included
- Fix auth header: X-API-Key not Authorization Bearer
- Remove fake output_schema from API snippet
- Update pharmacy count to 5 (add Guardian, Medicare)
- Update architecture diagram to show all 5 chains
- Remove unused REQUEST_STAGGER_MS constant
…acies

- Fix event field names: streaming_url (snake_case), event.result (not resultJson)
- Fix COMPLETE event check: type=COMPLETE + status=COMPLETED
- Restore Guardian and Medicare to PHARMACY_SITES
- Fix search URLs to match plan spec (key= for Long Chau, q= for Pharmacity)
…on partial success

- Hide LivePreviewGrid when isSearching becomes false (iframes removed from DOM)
- Suppress network error if results already received (connection drop after partial success)
- Mark elapsed as 'partial' when connection drops mid-stream with results
… drop

- setInterval sends ': keepalive' SSE comment every 15 seconds
- Prevents proxy/browser from killing idle connection during long TinyFish scrapes
- Cleared before controller.close() to avoid writing to closed stream
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 17, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 50c570f2-cd0c-4bff-87ab-3d0d2cd9bcf4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can suggest fixes for GitHub Check annotations.

Configure the reviews.tools.github-checks setting to adjust the time to wait for GitHub Checks to complete.

- Dosage forms: Viên nén→Tablet, Viên nang→Capsule, Siro→Syrup, etc.
- Stock status: Còn hàng→In Stock, Hết hàng→Out of Stock, Cần toa→Rx Required
- Error/empty states: Lỗi→Error, Không tìm thấy→No results found
- Contact for price, product count labels
- Product names remain Vietnamese (from pharmacy sites)
@giaphutran12
Copy link
Copy Markdown
Contributor Author

PR link: #84

Part of a 3-app contribution batch for Vietnamese market tools:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant