diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..dc8b5b4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,40 @@
+# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
+
+# dependencies
+node_modules/
+
+# Expo
+.expo/
+dist/
+web-build/
+
+# Native
+.kotlin/
+*.orig.*
+*.jks
+*.p8
+*.p12
+*.key
+*.mobileprovision
+
+# Metro
+.metro-health-check*
+
+# debug
+npm-debug.*
+yarn-debug.*
+yarn-error.*
+
+# macOS
+.DS_Store
+*.pem
+
+# local env files
+.env*.local
+
+# typescript
+*.tsbuildinfo
+
+# generated native folders
+/ios
+/android
diff --git a/.npmrc b/.npmrc
new file mode 100644
index 0000000..7f4c450
--- /dev/null
+++ b/.npmrc
@@ -0,0 +1 @@
+legacy-peer-deps=true
diff --git a/App.tsx b/App.tsx
new file mode 100644
index 0000000..4c058f6
--- /dev/null
+++ b/App.tsx
@@ -0,0 +1,223 @@
+import React, { useState } from 'react';
+import {
+ AppRegistry,
+ View,
+ Text,
+ FlatList,
+ TouchableOpacity,
+ StyleSheet,
+ ScrollView,
+ TextInput,
+ Alert
+} from 'react-native';
+
+// 10 PATIENTS DATA
+const DATA = [
+ {"id":"1","patientName":"John Doe","phone":"+91-9876543210","reason":"Teeth cleaning","timestamp":"Jan 16, 9:30 AM","status":"New","messages":["Need teeth cleaning appointment"]},
+ {"id":"2","patientName":"Jane Smith","phone":"+91-9876543211","reason":"Root canal pain","timestamp":"Jan 16, 10:15 AM","status":"New","messages":["Severe tooth pain, urgent"]},
+ {"id":"3","patientName":"Raj Patel","phone":"+91-9876543212","reason":"Braces consult","timestamp":"Jan 15, 2:30 PM","status":"In Progress","messages":["Braces treatment inquiry"]},
+ {"id":"4","patientName":"Priya Sharma","phone":"+91-9876543213","reason":"Regular checkup","timestamp":"Jan 14, 11:00 AM","status":"Done","messages":["Routine checkup completed"]},
+ {"id":"5","patientName":"Amit Kumar","phone":"+91-9876543214","reason":"Tooth extraction","timestamp":"Jan 16, 1:45 PM","status":"New","messages":["Need extraction consultation"]},
+ {"id":"6","patientName":"Sita Devi","phone":"+91-9876543215","reason":"Filling needed","timestamp":"Jan 13, 3:20 PM","status":"New","messages":["Cavity filling required"]},
+ {"id":"7","patientName":"Ravi Gupta","phone":"+91-9876543216","reason":"Whitening","timestamp":"Jan 12, 4:10 PM","status":"In Progress","messages":["Teeth whitening inquiry"]},
+ {"id":"8","patientName":"Neha Reddy","phone":"+91-9876543217","reason":"Wisdom tooth","timestamp":"Jan 15, 5:30 PM","status":"New","messages":["Wisdom tooth pain"]},
+ {"id":"9","patientName":"Vikram Singh","phone":"+91-9876543218","reason":"Dental x-ray","timestamp":"Jan 14, 10:45 AM","status":"Done","messages":["X-ray results ready"]},
+ {"id":"10","patientName":"Lakshmi Nair","phone":"+91-9876543219","reason":"Emergency","timestamp":"Jan 16, 8:20 AM","status":"New","messages":["Emergency appointment needed"]}
+];
+
+const getStatusColor = (status: string) => {
+ switch (status) {
+ case 'New': return '#10B981';
+ case 'In Progress': return '#F59E0B';
+ case 'Done': return '#8B5CF6';
+ default: return '#6B7280';
+ }
+};
+
+export default function App() {
+ const [currentScreen, setCurrentScreen] = useState('Inbox');
+ const [selectedPatient, setSelectedPatient] = useState(DATA[0]);
+ const [summaryText, setSummaryText] = useState('');
+ const [selectedOutcome, setSelectedOutcome] = useState('Scheduled');
+
+ // INBOX SCREEN
+ if (currentScreen === 'Inbox') {
+ const renderItem = ({ item }: { item: any }) => (
+ {
+ setSelectedPatient(item);
+ setCurrentScreen('Detail');
+ }}
+ activeOpacity={0.7}
+ >
+
+ {item.patientName}
+ {item.reason}
+ {item.timestamp}
+
+
+ {item.status}
+
+
+ );
+
+ return (
+
+ π¦· Dental Inbox (10 Patients)
+ item.id}
+ contentContainerStyle={styles.list}
+ />
+
+ );
+ }
+
+ // DETAIL SCREEN
+ if (currentScreen === 'Detail') {
+ return (
+
+ setCurrentScreen('Inbox')}
+ >
+ β Back to Inbox
+
+
+
+ {selectedPatient.patientName}
+ {selectedPatient.phone}
+ {selectedPatient.reason}
+ Created: {selectedPatient.timestamp}
+
+
+
+ π¬ Messages
+ {selectedPatient.messages.map((msg: string, index: number) => (
+
+ {msg}
+
+ ))}
+
+
+ setCurrentScreen('Summary')}
+ >
+ π Create Summary
+
+
+ );
+ }
+
+ // SUMMARY SCREEN
+ if (currentScreen === 'Summary') {
+ const saveSummary = () => {
+ if (!summaryText.trim()) {
+ Alert.alert('β Error', 'Please add a summary');
+ return;
+ }
+
+ Alert.alert(
+ 'β
Success!',
+ `Summary saved for ${selectedPatient.patientName}!\nStatus updated to "Done"`,
+ [{ text: 'OK', onPress: () => setCurrentScreen('Inbox') }]
+ );
+ };
+
+ return (
+
+ setCurrentScreen('Inbox')}
+ >
+ β Back to Inbox
+
+
+
+ {selectedPatient.patientName}
+ {selectedPatient.reason}
+
+
+
+ π Call Summary
+
+
+
+
+ π Outcome
+ {['Scheduled', 'Left Voicemail', 'Needs Follow-up', 'Not Interested'].map((option) => (
+ setSelectedOutcome(option)}
+ >
+
+ {option}
+
+
+ ))}
+
+
+
+ πΎ Save & Mark Done
+
+
+ );
+ }
+}
+
+AppRegistry.registerComponent('main', () => App);
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#f8fafc' },
+ header: { fontSize: 24, fontWeight: 'bold', color: 'white', backgroundColor: '#10B981', padding: 20, textAlign: 'center' },
+ list: { padding: 16, paddingBottom: 20 },
+ item: {
+ flexDirection: 'row',
+ backgroundColor: 'white',
+ padding: 20,
+ marginBottom: 12,
+ borderRadius: 16,
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: 4 },
+ shadowOpacity: 0.1,
+ shadowRadius: 12,
+ elevation: 4,
+ alignItems: 'center',
+ },
+ content: { flex: 1 },
+ patientName: { fontSize: 20, fontWeight: 'bold', marginBottom: 4, color: '#1e293b' },
+ reason: { fontSize: 16, color: '#64748b', marginBottom: 4 },
+ timestamp: { fontSize: 14, color: '#94a3b8' },
+ status: { paddingHorizontal: 16, paddingVertical: 8, borderRadius: 20, minWidth: 90, alignItems: 'center' },
+ statusText: { color: 'white', fontSize: 12, fontWeight: 'bold', textTransform: 'uppercase' },
+ backButton: { backgroundColor: '#f1f5f9', padding: 12, borderRadius: 12, margin: 16, alignItems: 'center' },
+ backButtonText: { color: '#64748b', fontSize: 16, fontWeight: '600' },
+ card: { backgroundColor: 'white', padding: 24, borderRadius: 16, marginBottom: 16, marginHorizontal: 16, shadowColor: '#000', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.1, shadowRadius: 12, elevation: 4 },
+ phone: { fontSize: 18, color: '#10B981', marginBottom: 8 },
+ messagesCard: { backgroundColor: 'white', padding: 24, borderRadius: 16, marginBottom: 16, marginHorizontal: 16, shadowColor: '#000', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.1, shadowRadius: 12, elevation: 4 },
+ sectionTitle: { fontSize: 20, fontWeight: 'bold', marginBottom: 16, color: '#1e293b' },
+ message: { backgroundColor: '#f1f5f9', padding: 12, borderRadius: 12, marginBottom: 8 },
+ messageText: { fontSize: 16, color: '#475569' },
+ createSummaryBtn: { backgroundColor: '#10B981', padding: 20, borderRadius: 16, alignItems: 'center', marginBottom: 20, marginHorizontal: 16, shadowColor: '#000', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.2, shadowRadius: 12, elevation: 4 },
+ createSummaryText: { color: 'white', fontSize: 18, fontWeight: 'bold' },
+ patientHeader: { backgroundColor: 'white', padding: 24, borderRadius: 16, marginBottom: 16, marginHorizontal: 16, shadowColor: '#000', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.1, shadowRadius: 12, elevation: 4 },
+ patientReason: { fontSize: 18, color: '#64748b', marginBottom: 8 },
+ textarea: { borderWidth: 1, borderColor: '#e2e8f0', borderRadius: 12, padding: 16, fontSize: 16, minHeight: 120, backgroundColor: '#fafbfc', textAlignVertical: 'top', marginHorizontal: 16 },
+ outcomeBtn: { backgroundColor: '#f8fafc', padding: 16, borderRadius: 12, marginBottom: 8, borderWidth: 2, borderColor: '#e2e8f0', marginHorizontal: 16 },
+ outcomeBtnSelected: { backgroundColor: '#10B981', borderColor: '#059669' },
+ outcomeBtnText: { fontSize: 16, color: '#64748b', textAlign: 'center', fontWeight: '500' },
+ outcomeBtnTextSelected: { color: 'white', fontWeight: 'bold' },
+ saveBtn: { backgroundColor: '#8B5CF6', padding: 20, borderRadius: 16, alignItems: 'center', marginBottom: 20, marginHorizontal: 16, shadowColor: '#000', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.2, shadowRadius: 12, elevation: 4 },
+ saveBtnText: { color: 'white', fontSize: 18, fontWeight: 'bold' }
+});
diff --git a/README.md b/README.md
deleted file mode 100644
index 11273f0..0000000
--- a/README.md
+++ /dev/null
@@ -1,200 +0,0 @@
-# Savvy Agents β React Native TakeβHome Assignment
-
----
-
-## π Getting Started
-
-### How to Submit
-
-1. **Fork this repository** to your own GitHub account
-2. **Clone your fork** locally
-3. **Create a new branch** from `main` (e.g., `feat/your-name-submission`)
-4. Build the app with incremental commits on your branch
-5. **Push your branch** to your forked repo
-6. **Create a Pull Request** from your branch to `main` in your fork
-
-> β οΈ **Important**: Do NOT push directly to `main`. Always work on a feature branch and submit via Pull Request.
-
----
-
-## π Learning Resources
-
-If you're new to Git or React Native, we recommend completing these courses before starting:
-
-### Git & Version Control
-- **[Git Me Some Version Control](https://laracasts.com/series/git-me-some-version-control)** (Laracasts)
-- *YouTube Alternative*: [Git and GitHub for Beginners - Crash Course](https://www.youtube.com/watch?v=RGOj5yH7evk) (freeCodeCamp)
-
-### React Native & Expo
-- **[Build Mobile Apps with React Native and Expo](https://laracasts.com/series/build-mobile-apps-with-react-native-and-expo)** (Laracasts)
-- *YouTube Alternatives*:
- - [React Native Tutorial for Beginners](https://www.youtube.com/watch?v=0-S5a0eXPoc) (Programming with Mosh)
- - [React Native Crash Course](https://www.youtube.com/watch?v=VozPNrt-LfE) (Traversy Media)
-
-> π‘ If you don't have access to Laracasts, the YouTube alternatives cover the same fundamentals.
-
----
-
-## Overview
-
-This assignment is designed to evaluate your fundamentals in **React Native**, your ability to learn independently, and how you structure, commit, and explain your code.
-
-You will build a small **mobile app** that simulates a dental office inbox where calls/conversations are listed, viewed, and summarized.
-
-This is **not a trick assignment**. We care more about **clarity, progress, and good habits** than perfection.
-
----
-
-## What Youβll Build
-
-A simple React Native app with **3 screens**:
-
-### 1. Inbox Screen
-
-* Displays a list of conversations (use fake data from a local JSON file).
-* Each item should show:
-
- * Patient name
- * Reason for call
- * Timestamp
- * Status (New / In Progress / Done)
-* Tapping a conversation opens the detail screen.
-
-### 2. Conversation Detail Screen
-
-* Shows full details of the conversation:
-
- * Patient name
- * Phone number
- * Reason for call
- * Created date/time
-* Shows a transcript/messages list (fake messages from JSON).
-* Button: **βCreate Summaryβ** β navigates to Summary screen.
-
-### 3. Summary Screen
-
-* Form to create a call summary:
-
- * Summary notes (multiline text input)
- * Outcome (Scheduled / Left Voicemail / Needs Followβup / Not Interested)
- * Next action date (simple text or date picker)
-* Save button:
-
- * Saves the summary locally
- * Marks the conversation as **Done**
- * Navigates back to Inbox
-
----
-
-## Data & Persistence
-
-* Start with a local `data.json` file containing ~10 conversations.
-* On app load:
-
- * Load conversations from JSON
- * Overlay any saved updates from local storage
-* Use **AsyncStorage** (or equivalent) to persist:
-
- * Summary data
- * Updated conversation status
-* Data must persist after app reload.
-
----
-
-## Tech Stack
-
-You may choose either:
-
-**Option A (Recommended)**
-
-* Expo
-* React Native
-* React Navigation
-* AsyncStorage
-
-**Option B**
-
-* React Native CLI
-* React Navigation
-* AsyncStorage
-
-Notes:
-
-* Functional components + hooks only
-* TypeScript is optional but encouraged
-* No backend required
-
----
-
-## Git & Workflow (Very Important)
-
-You must **push code incrementally** to GitHub.
-
-Minimum expected commits (example):
-
-1. `chore: initialize react native app`
-2. `feat: add inbox screen with conversation list`
-3. `feat: add navigation and conversation detail screen`
-4. `feat: add summary screen and form`
-5. `feat: persist data using asyncstorage`
-6. `ui: improve styling and status badge`
-7. `fix: handle loading and empty states`
-8. `docs: add readme and setup instructions`
-
-Additional requirements:
-
-* Push code regularly (at least 2β3 times per week)
-* Use clear, meaningful commit messages
-* Create at least **one pull request** into `main` (even if itβs your own repo)
-
----
-
-## UI Expectations
-
-* Clean and readable UI
-* Consistent spacing and typography
-* Status should be visually distinguishable (badge or label)
-* No need for fancy animations
-
----
-
-## Stretch Goals (Optional β pick 1 or 2)
-
-* Search conversations by patient name
-* Filter by status (All / New / Done)
-* Sort by newest
-* Basic form validation
-* Ability to edit a saved summary
-
----
-
-## Deliverables
-
-1. **GitHub repository link** (with visible commit history)
-2. **README** containing:
-
- * Setup instructions
- * Brief explanation of app structure
- * What you would improve if you had more time
-3. **Short demo video (2β4 minutes)** showing:
-
- * App navigation
- * Creating and saving a summary
- * Persistence after reload
-
----
-
-## Time & Expectations
-
-* Expected effort: **6β10 hours for MVP**
-* With polish/stretch goals: **10β20 hours**
-* Work at your own pace. Once you feel the assignment is complete and polished, share the GitHub repository URL.
-
-We care most about:
-
-* Learning ability
-* Code clarity
-* Git discipline
-* Communication
-
-Good luck β treat this like a real task π
diff --git a/app.json b/app.json
new file mode 100644
index 0000000..3389ed7
--- /dev/null
+++ b/app.json
@@ -0,0 +1,10 @@
+{
+ "expo": {
+ "name": "Dental Inbox",
+ "slug": "dental-inbox",
+ "version": "1.0.0",
+ "sdkVersion": "54.0.0",
+ "platforms": ["ios", "android", "web"],
+ "assetBundlePatterns": ["**/*"]
+ }
+}
diff --git a/data.json b/data.json
deleted file mode 100644
index 5e2b954..0000000
--- a/data.json
+++ /dev/null
@@ -1,182 +0,0 @@
-{
- "conversations": [
- {
- "id": "1",
- "patientName": "Sarah Johnson",
- "phone": "512-555-0142",
- "reason": "Teeth cleaning appointment",
- "createdAt": "2025-01-03T09:15:00Z",
- "status": "New",
- "messages": [
- {
- "id": "m1",
- "sender": "patient",
- "text": "Hi, I want to schedule a teeth cleaning.",
- "timestamp": "2025-01-03T09:15:00Z"
- },
- {
- "id": "m2",
- "sender": "assistant",
- "text": "Sure! Do you have any preferred dates?",
- "timestamp": "2025-01-03T09:16:00Z"
- }
- ]
- },
- {
- "id": "2",
- "patientName": "Michael Chen",
- "phone": "737-555-2218",
- "reason": "Tooth pain",
- "createdAt": "2025-01-04T11:42:00Z",
- "status": "In Progress",
- "messages": [
- {
- "id": "m1",
- "sender": "patient",
- "text": "I have a sharp pain in my lower molar.",
- "timestamp": "2025-01-04T11:42:00Z"
- },
- {
- "id": "m2",
- "sender": "assistant",
- "text": "Sorry to hear that. Is the pain constant or only when biting?",
- "timestamp": "2025-01-04T11:44:00Z"
- }
- ]
- },
- {
- "id": "3",
- "patientName": "Emily Rodriguez",
- "phone": "210-555-9081",
- "reason": "Insurance question",
- "createdAt": "2025-01-05T14:05:00Z",
- "status": "New",
- "messages": [
- {
- "id": "m1",
- "sender": "patient",
- "text": "Do you accept Delta Dental PPO?",
- "timestamp": "2025-01-05T14:05:00Z"
- }
- ]
- },
- {
- "id": "4",
- "patientName": "David Miller",
- "phone": "469-555-6623",
- "reason": "Crown follow-up",
- "createdAt": "2025-01-06T10:20:00Z",
- "status": "Done",
- "messages": [
- {
- "id": "m1",
- "sender": "patient",
- "text": "I had a crown placed last week and have some sensitivity.",
- "timestamp": "2025-01-06T10:20:00Z"
- },
- {
- "id": "m2",
- "sender": "assistant",
- "text": "That can be normal. We can schedule a quick follow-up if needed.",
- "timestamp": "2025-01-06T10:22:00Z"
- }
- ]
- },
- {
- "id": "5",
- "patientName": "Aisha Patel",
- "phone": "512-555-7749",
- "reason": "New patient appointment",
- "createdAt": "2025-01-07T16:30:00Z",
- "status": "New",
- "messages": [
- {
- "id": "m1",
- "sender": "patient",
- "text": "Iβm a new patient and would like to book an appointment.",
- "timestamp": "2025-01-07T16:30:00Z"
- }
- ]
- },
- {
- "id": "6",
- "patientName": "Robert Thompson",
- "phone": "830-555-1190",
- "reason": "Reschedule appointment",
- "createdAt": "2025-01-08T08:55:00Z",
- "status": "In Progress",
- "messages": [
- {
- "id": "m1",
- "sender": "patient",
- "text": "I need to reschedule my appointment tomorrow.",
- "timestamp": "2025-01-08T08:55:00Z"
- }
- ]
- },
- {
- "id": "7",
- "patientName": "Jessica Nguyen",
- "phone": "972-555-4821",
- "reason": "Whitening consultation",
- "createdAt": "2025-01-09T13:10:00Z",
- "status": "New",
- "messages": [
- {
- "id": "m1",
- "sender": "patient",
- "text": "Do you offer teeth whitening?",
- "timestamp": "2025-01-09T13:10:00Z"
- }
- ]
- },
- {
- "id": "8",
- "patientName": "Carlos Martinez",
- "phone": "956-555-3304",
- "reason": "Broken filling",
- "createdAt": "2025-01-10T17:45:00Z",
- "status": "In Progress",
- "messages": [
- {
- "id": "m1",
- "sender": "patient",
- "text": "My filling fell out while eating.",
- "timestamp": "2025-01-10T17:45:00Z"
- }
- ]
- },
- {
- "id": "9",
- "patientName": "Lauren Wilson",
- "phone": "512-555-6012",
- "reason": "Billing question",
- "createdAt": "2025-01-11T12:00:00Z",
- "status": "New",
- "messages": [
- {
- "id": "m1",
- "sender": "patient",
- "text": "I have a question about my last invoice.",
- "timestamp": "2025-01-11T12:00:00Z"
- }
- ]
- },
- {
- "id": "10",
- "patientName": "Brian O'Connor",
- "phone": "214-555-9987",
- "reason": "Emergency appointment",
- "createdAt": "2025-01-12T07:25:00Z",
- "status": "New",
- "messages": [
- {
- "id": "m1",
- "sender": "patient",
- "text": "I chipped my tooth this morning and need to be seen ASAP.",
- "timestamp": "2025-01-12T07:25:00Z"
- }
- ]
- }
- ]
-}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..abb30ef
--- /dev/null
+++ b/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "react-native-assignment",
+ "version": "1.0.0",
+ "main": "App.tsx",
+ "scripts": {
+ "start": "expo start",
+ "android": "expo start --android",
+ "ios": "expo start --ios"
+ },
+ "dependencies": {
+ "@react-native-async-storage/async-storage": "2.2.0",
+ "@react-navigation/native": "^6.1.9",
+ "@react-navigation/stack": "^6.3.20",
+ "@types/react": "~19.1.10",
+ "expo": "~54.0.31",
+ "react": "19.1.0",
+ "react-native": "0.81.5",
+ "react-native-safe-area-context": "~5.6.0",
+ "react-native-screens": "~4.16.0",
+ "typescript": "~5.9.2"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.20.0"
+ }
+}
diff --git a/src/data.json.txt b/src/data.json.txt
new file mode 100644
index 0000000..fde8574
--- /dev/null
+++ b/src/data.json.txt
@@ -0,0 +1,12 @@
+[
+ {"id":"1","patientName":"John Doe","phone":"+91-9876543210","reason":"Teeth cleaning","timestamp":"Jan 16, 9:30 AM","status":"New","messages":["Need teeth cleaning appointment","Routine cleaning scheduled"]},
+ {"id":"2","patientName":"Jane Smith","phone":"+91-9876543211","reason":"Root canal pain","timestamp":"Jan 16, 10:15 AM","status":"New","messages":["Severe tooth pain, urgent","Root canal needed"]},
+ {"id":"3","patientName":"Raj Patel","phone":"+91-9876543212","reason":"Braces consult","timestamp":"Jan 15, 2:30 PM","status":"In Progress","messages":["Braces treatment inquiry","Consultation ongoing"]},
+ {"id":"4","patientName":"Priya Sharma","phone":"+91-9876543213","reason":"Regular checkup","timestamp":"Jan 14, 11:00 AM","status":"Done","messages":["Routine checkup completed","All good"]},
+ {"id":"5","patientName":"Amit Kumar","phone":"+91-9876543214","reason":"Tooth extraction","timestamp":"Jan 16, 1:45 PM","status":"New","messages":["Need extraction consultation","Tooth pain increasing"]},
+ {"id":"6","patientName":"Sita Devi","phone":"+91-9876543215","reason":"Filling needed","timestamp":"Jan 13, 3:20 PM","status":"New","messages":["Cavity filling required","Right side molar"]},
+ {"id":"7","patientName":"Ravi Gupta","phone":"+91-9876543216","reason":"Whitening","timestamp":"Jan 12, 4:10 PM","status":"In Progress","messages":["Teeth whitening inquiry","Treatment started"]},
+ {"id":"8","patientName":"Neha Reddy","phone":"+91-9876543217","reason":"Wisdom tooth","timestamp":"Jan 15, 5:30 PM","status":"New","messages":["Wisdom tooth pain","Lower right side"]},
+ {"id":"9","patientName":"Vikram Singh","phone":"+91-9876543218","reason":"Dental x-ray","timestamp":"Jan 14, 10:45 AM","status":"Done","messages":["X-ray results ready","No issues found"]},
+ {"id":"10","patientName":"Lakshmi Nair","phone":"+91-9876543219","reason":"Emergency","timestamp":"Jan 16, 8:20 AM","status":"New","messages":["Emergency appointment needed","Broken tooth"]}
+]
diff --git a/src/hooks/useConversations.ts.txt b/src/hooks/useConversations.ts.txt
new file mode 100644
index 0000000..1a5df5e
--- /dev/null
+++ b/src/hooks/useConversations.ts.txt
@@ -0,0 +1,25 @@
+import { useEffect, useState } from 'react';
+import AsyncStorage from '@react-native-async-storage/async-storage';
+import data from '../data.json';
+
+export const useConversations = () => {
+ const [conversations, setConversations] = useState(data);
+
+ useEffect(() => {
+ const loadConversations = async () => {
+ try {
+ const saved = await AsyncStorage.getItem('conversations');
+ if (saved) {
+ setConversations(JSON.parse(saved));
+ }
+ } catch (error) {
+ console.log('Failed to load conversations:', error);
+ }
+ };
+ loadConversations();
+ }, []);
+
+ return conversations;
+};
+
+
diff --git a/src/screens/DetailScreen.tsx.txt b/src/screens/DetailScreen.tsx.txt
new file mode 100644
index 0000000..8aa6520
--- /dev/null
+++ b/src/screens/DetailScreen.tsx.txt
@@ -0,0 +1,110 @@
+import React, { useState, useEffect } from 'react';
+import { View, Text, ScrollView, TouchableOpacity, StyleSheet, SafeAreaView } from 'react-native';
+import AsyncStorage from '@react-native-async-storage/async-storage';
+import { RouteProp, useRoute, useNavigation } from '@react-navigation/native';
+
+type RootStackParamList = {
+ Detail: { conversationId: string };
+ Summary: { conversationId: string };
+};
+
+type Props = {
+ route: RouteProp;
+};
+
+export default function DetailScreen({ route }: Props) {
+ const navigation = useNavigation();
+ const { conversationId } = route.params;
+ const [conversation, setConversation] = useState(null);
+
+ useEffect(() => {
+ loadConversation();
+ }, []);
+
+ const loadConversation = async () => {
+ try {
+ const saved = await AsyncStorage.getItem('conversations');
+ const conversations = saved ? JSON.parse(saved) : require('../data.json');
+ const conv = conversations.find((c: any) => c.id === conversationId);
+ setConversation(conv);
+ } catch (error) {
+ console.log('Load conversation failed');
+ }
+ };
+
+ if (!conversation) return null;
+
+ return (
+
+
+
+ {conversation.patientName}
+
+ π Phone:
+ {conversation.phone}
+
+
+ π― Reason:
+ {conversation.reason}
+
+
+ π
Time:
+ {conversation.timestamp}
+
+
+ π Status:
+ {conversation.status}
+
+
+
+ π¬ Messages:
+ {conversation.messages.map((msg: string, index: number) => (
+
+ {msg}
+
+ ))}
+
+
+
+
+ navigation.navigate('Summary', { conversationId })}
+ >
+ π Create Summary
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#f8fafc' },
+ scrollView: { flex: 1, padding: 20 },
+ card: {
+ backgroundColor: 'white',
+ padding: 24,
+ borderRadius: 20,
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: 4 },
+ shadowOpacity: 0.1,
+ shadowRadius: 12,
+ elevation: 4,
+ },
+ patientName: { fontSize: 28, fontWeight: 'bold', color: '#1e293b', marginBottom: 24, textAlign: 'center' },
+ infoRow: { flexDirection: 'row', marginBottom: 16, alignItems: 'center' },
+ label: { fontSize: 16, fontWeight: '600', color: '#64748b', minWidth: 100 },
+ info: { fontSize: 16, color: '#1e293b', flex: 1 },
+ status: { fontSize: 16, fontWeight: 'bold' },
+ section: { marginTop: 24 },
+ sectionTitle: { fontSize: 18, fontWeight: 'bold', color: '#1e293b', marginBottom: 16 },
+ message: { backgroundColor: '#f1f5f9', padding: 16, borderRadius: 12, marginBottom: 12 },
+ messageText: { fontSize: 16, color: '#1e293b' },
+ createSummaryButton: {
+ backgroundColor: '#10B981',
+ padding: 20,
+ borderRadius: 16,
+ margin: 20,
+ alignItems: 'center'
+ },
+ createSummaryButtonText: { color: 'white', fontSize: 18, fontWeight: 'bold' }
+});
diff --git a/src/screens/InboxScreen.tsx.txt b/src/screens/InboxScreen.tsx.txt
new file mode 100644
index 0000000..4f00875
--- /dev/null
+++ b/src/screens/InboxScreen.tsx.txt
@@ -0,0 +1,129 @@
+import React, { useState, useEffect } from 'react';
+import {
+ View,
+ Text,
+ FlatList,
+ TouchableOpacity,
+ StyleSheet,
+ Alert
+} from 'react-native';
+import AsyncStorage from '@react-native-async-storage/async-storage';
+import data from '../data.json';
+
+const getStatusColor = (status: string) => {
+ switch (status) {
+ case 'New': return '#10B981';
+ case 'In Progress': return '#F59E0B';
+ case 'Done': return '#8B5CF6';
+ default: return '#6B7280';
+ }
+};
+
+export default function InboxScreen({ navigation }: any) {
+ const [conversations, setConversations] = useState(data);
+
+ useEffect(() => {
+ loadConversations();
+ }, []);
+
+ const loadConversations = async () => {
+ try {
+ const saved = await AsyncStorage.getItem('conversations');
+ if (saved) {
+ setConversations(JSON.parse(saved));
+ }
+ } catch (error) {
+ console.log('Load error:', error);
+ }
+ };
+
+ const handlePress = (conversation: any) => {
+ console.log('Navigating to Detail:', conversation.id);
+ navigation.navigate('Detail', { conversation });
+ };
+
+ const renderItem = ({ item }: { item: any }) => (
+ handlePress(item)}
+ activeOpacity={0.7}
+ >
+
+ {item.patientName}
+ {item.reason}
+ {item.timestamp}
+
+
+ {item.status}
+
+
+ );
+
+ return (
+
+ item.id}
+ contentContainerStyle={styles.list}
+ showsVerticalScrollIndicator={false}
+ />
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: '#f8fafc',
+ paddingTop: 10
+ },
+ list: {
+ padding: 16,
+ paddingBottom: 20
+ },
+ item: {
+ flexDirection: 'row',
+ backgroundColor: 'white',
+ padding: 20,
+ marginBottom: 12,
+ borderRadius: 16,
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: 4 },
+ shadowOpacity: 0.1,
+ shadowRadius: 12,
+ elevation: 4,
+ alignItems: 'center',
+ },
+ content: {
+ flex: 1
+ },
+ patientName: {
+ fontSize: 20,
+ fontWeight: 'bold',
+ marginBottom: 4,
+ color: '#1e293b'
+ },
+ reason: {
+ fontSize: 16,
+ color: '#64748b',
+ marginBottom: 4
+ },
+ timestamp: {
+ fontSize: 14,
+ color: '#94a3b8'
+ },
+ status: {
+ paddingHorizontal: 16,
+ paddingVertical: 8,
+ borderRadius: 20,
+ minWidth: 90,
+ alignItems: 'center'
+ },
+ statusText: {
+ color: 'white',
+ fontSize: 12,
+ fontWeight: 'bold',
+ textTransform: 'uppercase'
+ }
+});
diff --git a/src/screens/SummaryScreen.tsx.txt b/src/screens/SummaryScreen.tsx.txt
new file mode 100644
index 0000000..da40c1a
--- /dev/null
+++ b/src/screens/SummaryScreen.tsx.txt
@@ -0,0 +1,323 @@
+import React, { useState, useEffect } from 'react';
+import {
+ View,
+ Text,
+ TextInput,
+ TouchableOpacity,
+ StyleSheet,
+ ScrollView,
+ Alert,
+ Switch
+} from 'react-native';
+import AsyncStorage from '@react-native-async-storage/async-storage';
+
+export default function SummaryScreen({ route, navigation }: any) {
+ const { conversation } = route.params;
+ const [summary, setSummary] = useState('');
+ const [outcome, setOutcome] = useState('Scheduled');
+ const [nextActionDate, setNextActionDate] = useState('');
+ const [isLoading, setIsLoading] = useState(false);
+
+ // Load existing summary if available
+ useEffect(() => {
+ loadSummary();
+ }, []);
+
+ const loadSummary = async () => {
+ try {
+ const saved = await AsyncStorage.getItem('conversations');
+ if (saved) {
+ const conversations = JSON.parse(saved);
+ const found = conversations.find((c: any) => c.id === conversation.id);
+ if (found?.summary) {
+ setSummary(found.summary.notes || '');
+ setOutcome(found.summary.outcome || 'Scheduled');
+ setNextActionDate(found.summary.nextActionDate || '');
+ }
+ }
+ } catch (error) {
+ console.log('Load summary error:', error);
+ }
+ };
+
+ const saveSummary = async () => {
+ if (!summary.trim()) {
+ Alert.alert('β Error', 'Please add a summary of the call');
+ return;
+ }
+
+ setIsLoading(true);
+ try {
+ // Create summary object
+ const summaryData = {
+ notes: summary,
+ outcome,
+ nextActionDate: nextActionDate || 'None',
+ savedAt: new Date().toLocaleString('en-IN', {
+ day: '2-digit',
+ month: 'short',
+ year: 'numeric',
+ hour: '2-digit',
+ minute: '2-digit'
+ })
+ };
+
+ // Update conversation
+ const updatedConversation = {
+ ...conversation,
+ status: 'Done',
+ summary: summaryData
+ };
+
+ // Save to AsyncStorage
+ const saved = await AsyncStorage.getItem('conversations');
+ const conversations = saved ? JSON.parse(saved) : [];
+
+ const existingIndex = conversations.findIndex((c: any) => c.id === conversation.id);
+ if (existingIndex !== -1) {
+ conversations[existingIndex] = updatedConversation;
+ } else {
+ conversations.push(updatedConversation);
+ }
+
+ await AsyncStorage.setItem('conversations', JSON.stringify(conversations));
+
+ Alert.alert(
+ 'β
Success!',
+ `Summary saved for ${conversation.patientName}\nStatus updated to "Done"`,
+ [{ text: 'OK', onPress: () => navigation.navigate('Inbox') }]
+ );
+ } catch (error) {
+ Alert.alert('β Error', 'Failed to save summary. Please try again.');
+ console.log('Save error:', error);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ return (
+
+ {/* Patient Info Header */}
+
+ {conversation.patientName}
+ {conversation.reason}
+ π {conversation.phone}
+
+
+ {/* Summary Notes */}
+
+ π Call Summary
+
+
+
+ {/* Outcome Selection */}
+
+ π Call Outcome
+
+ {[
+ { label: 'β
Scheduled', value: 'Scheduled', color: '#10B981' },
+ { label: 'π Left Voicemail', value: 'Left Voicemail', color: '#F59E0B' },
+ { label: 'β³ Needs Follow-up', value: 'Needs Follow-up', color: '#3B82F6' },
+ { label: 'β Not Interested', value: 'Not Interested', color: '#EF4444' }
+ ].map((option) => (
+ setOutcome(option.value)}
+ disabled={isLoading}
+ >
+
+ {option.label}
+
+
+ ))}
+
+
+
+ {/* Next Action */}
+
+ π
Next Action Date
+
+ Leave empty if no follow-up needed
+
+
+ {/* Save Button */}
+
+
+ {isLoading ? 'πΎ Saving...' : 'πΎ Save Summary & Mark Done'}
+
+
+
+ {/* Cancel Button */}
+ navigation.goBack()}
+ disabled={isLoading}
+ >
+ β Cancel
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: '#f8fafc',
+ padding: 16,
+ paddingTop: 10,
+ },
+ patientHeader: {
+ backgroundColor: 'white',
+ padding: 24,
+ borderRadius: 16,
+ marginBottom: 16,
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: 4 },
+ shadowOpacity: 0.1,
+ shadowRadius: 12,
+ elevation: 4,
+ },
+ patientName: {
+ fontSize: 28,
+ fontWeight: 'bold',
+ color: '#1e293b',
+ marginBottom: 4,
+ },
+ patientReason: {
+ fontSize: 18,
+ color: '#64748b',
+ marginBottom: 8,
+ },
+ patientPhone: {
+ fontSize: 16,
+ color: '#10B981',
+ fontWeight: '500',
+ },
+ card: {
+ backgroundColor: 'white',
+ padding: 20,
+ borderRadius: 16,
+ marginBottom: 16,
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: 4 },
+ shadowOpacity: 0.1,
+ shadowRadius: 12,
+ elevation: 4,
+ },
+ sectionTitle: {
+ fontSize: 18,
+ fontWeight: 'bold',
+ marginBottom: 12,
+ color: '#1e293b',
+ },
+ textarea: {
+ borderWidth: 1,
+ borderColor: '#e2e8f0',
+ borderRadius: 12,
+ padding: 16,
+ fontSize: 16,
+ minHeight: 120,
+ backgroundColor: '#fafbfc',
+ },
+ input: {
+ borderWidth: 1,
+ borderColor: '#e2e8f0',
+ borderRadius: 12,
+ padding: 16,
+ fontSize: 16,
+ backgroundColor: '#fafbfc',
+ },
+ outcomeContainer: {
+ gap: 12,
+ },
+ outcomeBtn: {
+ backgroundColor: '#f8fafc',
+ padding: 16,
+ borderRadius: 12,
+ borderWidth: 2,
+ borderColor: '#e2e8f0',
+ },
+ outcomeBtnSelected: {
+ backgroundColor: '#10B981',
+ borderColor: '#059669',
+ shadowColor: '#10B981',
+ shadowOffset: { width: 0, height: 2 },
+ shadowOpacity: 0.3,
+ shadowRadius: 8,
+ elevation: 3,
+ },
+ outcomeBtnText: {
+ fontSize: 16,
+ color: '#64748b',
+ textAlign: 'center',
+ fontWeight: '500',
+ },
+ outcomeBtnTextSelected: {
+ color: 'white',
+ fontWeight: 'bold',
+ },
+ helperText: {
+ fontSize: 14,
+ color: '#94a3b8',
+ marginTop: 8,
+ },
+ saveBtn: {
+ backgroundColor: '#8B5CF6',
+ padding: 20,
+ borderRadius: 16,
+ alignItems: 'center',
+ marginBottom: 12,
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: 4 },
+ shadowOpacity: 0.2,
+ shadowRadius: 12,
+ elevation: 4,
+ },
+ saveBtnDisabled: {
+ backgroundColor: '#a5b4fc',
+ },
+ saveBtnText: {
+ color: 'white',
+ fontSize: 18,
+ fontWeight: 'bold',
+ },
+ cancelBtn: {
+ backgroundColor: '#f1f5f9',
+ padding: 16,
+ borderRadius: 12,
+ borderWidth: 1,
+ borderColor: '#e2e8f0',
+ alignItems: 'center',
+ },
+ cancelBtnText: {
+ color: '#64748b',
+ fontSize: 16,
+ fontWeight: '600',
+ },
+});
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..0e6371f
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,4 @@
+{
+ "compilerOptions": {},
+ "extends": "expo/tsconfig.base"
+}