Skip to content
Merged
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
12 changes: 12 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"expo-font": "~14.0.11",
"expo-linear-gradient": "~15.0.8",
"expo-status-bar": "~3.0.9",
"lucide-react-native": "^1.12.0",
"nativewind": "^4.2.1",
"react": "19.1.0",
"react-dom": "19.1.0",
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/AddFoodModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export function AddFoodModal({ visible, onClose }: Props) {
placeholder="e.g. Milk, Wheat, Soy..."
chipClassName='bg-remetra-burgundy'
chipTextClassName='text-white'
removeTextClassName='text-white'
removeIconColor='#ffffff'
onAdd={(ing) => setIngredients((prev) => [...prev, ing])}
onRemove={(i) => setIngredients((prev) => prev.filter((_, idx) => idx !== i))}
/>
Expand Down
6 changes: 5 additions & 1 deletion frontend/src/components/BarcodeScannerScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { View, Text, TouchableOpacity, TextInput, StyleSheet } from "react-native";

Check warning on line 1 in frontend/src/components/BarcodeScannerScreen.tsx

View workflow job for this annotation

GitHub Actions / lint-and-test

'TextInput' is defined but never used

Check warning on line 1 in frontend/src/components/BarcodeScannerScreen.tsx

View workflow job for this annotation

GitHub Actions / lint-and-test

'TextInput' is defined but never used
import { useNavigation, useRoute } from "@react-navigation/native";

Check warning on line 2 in frontend/src/components/BarcodeScannerScreen.tsx

View workflow job for this annotation

GitHub Actions / lint-and-test

'useRoute' is defined but never used

Check warning on line 2 in frontend/src/components/BarcodeScannerScreen.tsx

View workflow job for this annotation

GitHub Actions / lint-and-test

'useRoute' is defined but never used
import { CameraView, useCameraPermissions } from "expo-camera";
import { ArrowLeft } from "lucide-react-native";
import { useState, useRef } from "react";
import { useBankStore } from "../store/bankStore";

Expand Down Expand Up @@ -91,7 +92,10 @@
<View style={styles.overlay}>
<Text style={styles.instructions}>Point at a barcode</Text>
<TouchableOpacity style={styles.cancelBtn} onPress={() => navigation.goBack()}>
<Text style={styles.cancelText}>← Cancel</Text>
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
<ArrowLeft size={18} color="#eea487" strokeWidth={2} />
<Text style={styles.cancelText}>Cancel</Text>
</View>
</TouchableOpacity>
{scanned && (
<TouchableOpacity style={styles.btn} onPress={() => setScanned(false)}>
Expand Down
30 changes: 19 additions & 11 deletions frontend/src/components/FoodLogForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { useUIStore } from "../store/uiStore";
import { useState, useEffect } from "react";
import { View, Text, TouchableOpacity, TextInput } from "react-native";
import { ArrowLeft, Camera } from "lucide-react-native";
import { LogDateTimePicker } from "./LogDateTimePicker";

interface FoodLogFormProps {
Expand Down Expand Up @@ -35,7 +36,7 @@
setIsCustom(true);
setScannedFood(null);
}
}, []);

Check warning on line 39 in frontend/src/components/FoodLogForm.tsx

View workflow job for this annotation

GitHub Actions / lint-and-test

React Hook useEffect has missing dependencies: 'scannedFood' and 'setScannedFood'. Either include them or remove the dependency array

Check warning on line 39 in frontend/src/components/FoodLogForm.tsx

View workflow job for this annotation

GitHub Actions / lint-and-test

React Hook useEffect has missing dependencies: 'scannedFood' and 'setScannedFood'. Either include them or remove the dependency array

const [servings, setServings] = useState("1");
const [timestamp, setTimestamp] = useState(new Date());
Expand Down Expand Up @@ -96,28 +97,35 @@

return (
<View className="pb-10">
<TouchableOpacity onPress={() => {
if (!selectedFood && !isCustom) {
onBack()
} else {
setIsCustom(false); setSearchQuery(""); setSelectedFood(null)
}
}}>
<Text className="text-base font-ptserif text-remetra-burgundy mb-4">← Back</Text>
<TouchableOpacity
onPress={() => {
if (!selectedFood && !isCustom) {
onBack()
} else {
setIsCustom(false); setSearchQuery(""); setSelectedFood(null)
}
}}
className="flex-row items-center gap-1.5 mb-4"
hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}
>
<ArrowLeft size={18} color="#B8624F" strokeWidth={2} />
<Text className="text-base font-ptserif text-remetra-burgundy">Back</Text>
</TouchableOpacity>
<View className="flex-row justify-between items-center mb-3">
<Text className="text-2xl font-bold font-ptserif text-remetra-espresso">
Log Food
</Text>
{!selectedFood && !isCustom && (
<TouchableOpacity
className="border border-remetra-burgundy/80 bg-remetra-burgundy/80 rounded-full py-1 px-2"
className="border border-remetra-burgundy/80 bg-remetra-burgundy/80 rounded-full p-2"
onPress={() => {
onCloseModal();
setTimeout(() => navigation.navigate('BarcodeScanner'), 300);
}}
hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}
accessibilityLabel="Scan Barcode"
>
<Text className="text-s font-ptserif text-white">Scan Barcode</Text>
<Camera size={18} color="#ffffff" strokeWidth={2} />
</TouchableOpacity>
)}
</View>
Expand Down Expand Up @@ -187,7 +195,7 @@
placeholder="Add Ingredients..."
chipClassName='bg-remetra-burgundy/80'
chipTextClassName='text-white'
removeTextClassName='text-white'
removeIconColor='#ffffff'
onAdd={(ing) => setCustomIngredients((prev) => [...prev, ing])}
onRemove={(i) => setCustomIngredients((prev) => prev.filter((_, idx) => idx !== i))}
/>
Expand Down
9 changes: 5 additions & 4 deletions frontend/src/components/GenericChipComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
TextInput,
TouchableOpacity,
} from "react-native";
import { X } from "lucide-react-native";

interface ChipsProps {
items: string[];
Expand All @@ -14,7 +15,7 @@ interface ChipsProps {
onRemove: (index: number) => void;
chipClassName?: string;
chipTextClassName?: string;
removeTextClassName?: string;
removeIconColor?: string;
}

export const Chips: React.FC<ChipsProps> = ({
Expand All @@ -25,7 +26,7 @@ export const Chips: React.FC<ChipsProps> = ({
onRemove,
chipClassName = "bg-neutral-200",
chipTextClassName = "text-neutral-700",
removeTextClassName = "text-neutral-500"
removeIconColor = "#737373"
}) => {
const [input, setInput] = useState("");

Expand All @@ -45,8 +46,8 @@ export const Chips: React.FC<ChipsProps> = ({
className={`flex-row items-center rounded-full py-1.5 px-3 gap-1.5 ${chipClassName}`}
>
<Text className={`text-sm ${chipTextClassName}`}>{item}</Text>
<TouchableOpacity onPress={() => onRemove(i)}>
<Text className={`text-sm font-semibold ${removeTextClassName}`}>✕</Text>
<TouchableOpacity onPress={() => onRemove(i)} hitSlop={{ top: 6, bottom: 6, left: 6, right: 6 }}>
<X size={14} color={removeIconColor} strokeWidth={2.5} />
</TouchableOpacity>
</View>
))}
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/components/ItemBank.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { View, Text, TouchableOpacity } from 'react-native';
import { X } from 'lucide-react-native';

interface ItemBankProps {
title: string;
Expand Down Expand Up @@ -36,8 +37,9 @@ export function ItemBank({
<TouchableOpacity
onPress={() => onRemove(item.id)}
hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}
className="mr-2"
>
<Text className="text-remetra-rose text-sm mr-2 font-bold">✕</Text>
<X size={14} color="#C85A4A" strokeWidth={2.5} />
</TouchableOpacity>
<Text className="text-remetra-espresso font-ptserif text-sm">
{item.name}
Expand Down
9 changes: 5 additions & 4 deletions frontend/src/components/LogEntryModal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Modal, ScrollView, View, TouchableOpacity, Text } from "react-native";
import { useState, useEffect } from "react";
import { X, Utensils, Stethoscope } from "lucide-react-native";

import { LogEntry, ModalStep } from "../types/logs";
import { FoodLogForm } from "./FoodLogForm";
Expand Down Expand Up @@ -49,8 +50,8 @@ const LogEntryModal: React.FC<LogEntryModalProps> = ({ visible, onClose, onLogEn
onStartShouldSetResponder={() => true}
>
<View className="flex-row justify-end px-4 pt-3">
<TouchableOpacity onPress={handleClose}>
<Text className="text-xl p-1 font-ptserif text-remetra-accent">✕</Text>
<TouchableOpacity onPress={handleClose} hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}>
<X size={22} color="#eea487" strokeWidth={2.25} />
</TouchableOpacity>
</View>

Expand All @@ -65,15 +66,15 @@ const LogEntryModal: React.FC<LogEntryModalProps> = ({ visible, onClose, onLogEn
className="w-full flex-row items-center gap-4 border border-remetra-burgundy rounded-2xl p-5 bg-remetra-orange/10"
onPress={() => setStep("food")}
>
<Text className="text-3xl">🍽</Text>
<Utensils size={20} color="#5C2E14" strokeWidth={1.75} />
<Text className="text-lg font-semibold font-ptserif text-remetra-espresso">Food</Text>
</TouchableOpacity>

<TouchableOpacity
className="w-full flex-row items-center gap-4 border border-remetra-burgundy rounded-2xl p-5 bg-remetra-orange/10"
onPress={() => setStep("symptom")}
>
<Text className="text-3xl">🩺</Text>
<Stethoscope size={20} color="#5C2E14" strokeWidth={1.75} />
<Text className="text-lg font-semibold font-ptserif text-remetra-espresso">Symptom</Text>
</TouchableOpacity>
</View>
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/SymptomCard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useState } from 'react';
import { Text, TouchableOpacity, View } from 'react-native';
import { Check } from 'lucide-react-native';
import { symptomLogService } from '../api/symptom_log_service';
import { LogDateTimePicker } from './LogDateTimePicker';
import { SymptomTimelineEntry } from '../types/timeline';
Expand Down Expand Up @@ -142,7 +143,7 @@ export function SymptomCard({
hasDuration ? 'bg-remetra-burgundy border-remetra-burgundy' : 'bg-white border-remetra-border'
}`}
>
{hasDuration ? <Text className="text-white text-xs">✓</Text> : null}
{hasDuration ? <Check size={12} color="#ffffff" strokeWidth={3} /> : null}
</TouchableOpacity>
<Text style={{ fontSize: 13, color: '#7B3B4E' }}>Duration (minutes)</Text>
</View>
Expand Down
26 changes: 15 additions & 11 deletions frontend/src/components/SymptomLogForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { symptomLogService } from "../api/symptom_log_service";
import { useAuthStore } from "../store/useAuthStore";
import { useState } from "react";
import { View, Text, TouchableOpacity, TextInput } from "react-native";
import { ArrowLeft } from "lucide-react-native";
import { Dropdown } from "react-native-element-dropdown";
import { LogDateTimePicker } from "./LogDateTimePicker";
import { sensationOptions, locationOptions } from "../types/symptomOptions";
Expand Down Expand Up @@ -100,17 +101,20 @@ export const SymptomLogForm: React.FC<SymptomLogFormProps> = ({ onSubmit, onBack

return (
<View className="pb-10">
<TouchableOpacity onPress={() => {
if (!selectedSymptom && !isCustom) {
onBack()
} else {
setIsCustom(false); setSearchQuery(""); setSelectedSymptom(null);
setCustomSensation(""); setCustomLocation("");
}
onBack
}
}>
<Text className="text-base font-ptserif text-remetra-espresso mb-4">← Back</Text>
<TouchableOpacity
onPress={() => {
if (!selectedSymptom && !isCustom) {
onBack()
} else {
setIsCustom(false); setSearchQuery(""); setSelectedSymptom(null);
setCustomSensation(""); setCustomLocation("");
}
}}
className="flex-row items-center gap-1.5 mb-4"
hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}
>
<ArrowLeft size={18} color="#5C2E14" strokeWidth={2} />
<Text className="text-base font-ptserif text-remetra-espresso">Back</Text>
</TouchableOpacity>

<Text className="text-2xl font-bold font-ptserif mb-3 text-remetra-espresso">
Expand Down
16 changes: 10 additions & 6 deletions frontend/src/navigation/MainTabs.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React from 'react';
import { View, Text } from 'react-native';
import { View } from 'react-native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { TimelineScreen } from '../screens/main/TimelineScreen';
import { AnalysisScreen } from '../screens/main/AnalysisScreen';
import { ProfileScreen } from '../screens/main/ProfileScreen';
import LogEntryModal from '../components/LogEntryModal';
import { useUIStore } from '../store/uiStore';
import { ClipboardList, ChartColumn, User, type LucideIcon } from 'lucide-react-native';

export type MainTabParamList = {
History: undefined;
Expand All @@ -15,10 +16,13 @@ export type MainTabParamList = {

const Tab = createBottomTabNavigator<MainTabParamList>();

function TabIcon({ emoji, focused }: { emoji: string; focused: boolean }) {
const TAB_ACTIVE_COLOR = '#B8624F';
const TAB_INACTIVE_COLOR = '#b2939b';

function TabIcon({ Icon, focused }: { Icon: LucideIcon; focused: boolean }) {
return (
<View style={{ alignItems: 'center', gap: 2 }}>
<Text style={{ fontSize: 20 }}>{emoji}</Text>
<Icon size={24} color={focused ? TAB_ACTIVE_COLOR : TAB_INACTIVE_COLOR} strokeWidth={focused ? 2.25 : 2} />
</View>
);
}
Expand Down Expand Up @@ -54,7 +58,7 @@ export function MainTabs() {
component={TimelineScreen}
options={{
tabBarIcon: ({ focused }) => (
<TabIcon emoji="📋" focused={focused} />
<TabIcon Icon={ClipboardList} focused={focused} />
),
}}
/>
Expand All @@ -63,7 +67,7 @@ export function MainTabs() {
component={AnalysisScreen}
options={{
tabBarIcon: ({ focused }) => (
<TabIcon emoji="📊"focused={focused} />
<TabIcon Icon={ChartColumn} focused={focused} />
),
}}
/>
Expand All @@ -72,7 +76,7 @@ export function MainTabs() {
component={ProfileScreen}
options={{
tabBarIcon: ({ focused }) => (
<TabIcon emoji="👤" focused={focused} />
<TabIcon Icon={User} focused={focused} />
),
}}
/>
Expand Down
22 changes: 15 additions & 7 deletions frontend/src/screens/main/AboutScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import React from 'react';
import { View, Text, TouchableOpacity, ScrollView, Linking } from 'react-native';
import {
HeartPlus,
NotebookPen,
Search,
ChartColumn,
ChevronRight,
type LucideIcon,
} from 'lucide-react-native';
import { BackgroundGradient } from '../../components/BackgroundGradient';

const CONTACT_EMAIL = 'hello@remetra.app';
Expand All @@ -12,7 +20,7 @@ export function AboutScreen() {
{/* Hero */}
<View className="items-center mb-8 mt-2">
<View className="w-24 h-24 rounded-full bg-remetra-peach justify-center items-center mb-3">
<Text className="text-5xl">⚕️</Text>
<HeartPlus size={44} color="#5C2E14" strokeWidth={1.75} />
</View>
<Text className="text-2xl font-semibold text-remetra-mauve italic tracking-[2px]">
REMETRA
Expand All @@ -35,9 +43,9 @@ export function AboutScreen() {
{/* How it works */}
<SectionDivider label="How It Works" />
<View className="gap-3">
<InfoRow emoji="📝" label="Lorem ipsum dolor sit amet" />
<InfoRow emoji="🔍" label="Consectetur adipiscing elit" />
<InfoRow emoji="📊" label="Sed do eiusmod tempor incididunt" />
<InfoRow Icon={NotebookPen} label="Lorem ipsum dolor sit amet" />
<InfoRow Icon={Search} label="Consectetur adipiscing elit" />
<InfoRow Icon={ChartColumn} label="Sed do eiusmod tempor incididunt" />
</View>

{/* Links */}
Expand Down Expand Up @@ -87,10 +95,10 @@ function SectionDivider({ label }: { label: string }) {
);
}

function InfoRow({ emoji, label }: { emoji: string; label: string }) {
function InfoRow({ Icon, label }: { Icon: LucideIcon; label: string }) {
return (
<View className="bg-white/70 rounded-xl p-4 flex-row items-center gap-3">
<Text className="text-xl">{emoji}</Text>
<Icon size={20} color="#5C2E14" strokeWidth={2} />
<Text className="text-[15px] text-neutral-700 flex-1">{label}</Text>
</View>
);
Expand All @@ -103,7 +111,7 @@ function LinkRow({ label, onPress }: { label: string; onPress: () => void }) {
className="bg-white/70 rounded-xl p-4 flex-row items-center gap-3"
>
<Text className="text-[15px] text-neutral-700 flex-1">{label}</Text>
<Text className="text-lg text-remetra-border">›</Text>
<ChevronRight size={20} color="#ccc" strokeWidth={2} />
</TouchableOpacity>
);
}
Loading
Loading