import { useState } from "react"; import { View, Text, TextInput, Pressable, ScrollView, Alert, KeyboardAvoidingView, Platform } from "react-native"; import { useTranslation } from "react-i18next"; import { useNavigation } from "@react-navigation/native"; import type { NativeStackNavigationProp } from "@react-navigation/native-stack"; import type { RootStackParamList } from "@navigation/types"; import { useWorkoutBuilder } from "../hooks/useWorkoutBuilder"; import { useSettings } from "../../../providers/WatchProvider"; import type { StrokeType } from "@/types/workout"; const STROKES: StrokeType[] = ["Freestyle", "Backstroke", "Breaststroke", "Butterfly", "Mixed"]; export function BuilderScreen() { const { t } = useTranslation("workout"); const { t: tc } = useTranslation("common"); const { t: tb } = useTranslation("navigation"); const navigation = useNavigation>(); const { poolLength: defaultPoolLength } = useSettings(); const [poolLength, setPoolLength] = useState(defaultPoolLength); const [fieldValues, setFieldValues] = useState>({}); const { sets, workoutName, setWorkoutName, totalDistance, isSaving, addSet, updateSet, removeSet, save, } = useWorkoutBuilder(); const handleSave = async () => { try { const workoutId = await save(poolLength); navigation.navigate("PreSwim", { workoutId }); } catch (e) { console.error("Failed to save workout:", e); Alert.alert(tc("validation.error"), tc("validation.failedToSave", { error: String(e) })); } }; return ( {tb("buildWorkout")} {totalDistance}m total ยท {tc("pool", { length: poolLength })} {t("workoutName")} {t("poolLength")} {[25, 50].map((length) => ( setPoolLength(length)} className={`flex-1 py-2.5 rounded-xl items-center ${ poolLength === length ? "bg-sky-500" : "bg-slate-100" }`} > {length}m ))} {sets.map((set, index) => ( {t("setNumber", { number: index + 1 })} {sets.length > 1 && ( removeSet(index)}> {t("remove")} )} {t("stroke")} {STROKES.map((stroke) => ( updateSet(index, { stroke })} className={`mr-2 px-3 py-1.5 rounded-full ${ set.stroke === stroke ? "bg-sky-500" : "bg-slate-200" }`} > {tc(`stroke.${stroke.toLowerCase()}`)} ))} {t("distanceM")} setFieldValues((prev) => ({ ...prev, [`${index}-distance`]: val }))} onBlur={() => { const num = Number(fieldValues[`${index}-distance`] ?? set.distancePerRep); updateSet(index, { distancePerRep: isNaN(num) || num < poolLength ? poolLength : num }); setFieldValues((prev) => { const next = { ...prev }; delete next[`${index}-distance`]; return next; }); }} placeholder={String(poolLength)} placeholderTextColor="#94a3b8" className="bg-white border border-slate-300 rounded-lg px-3 py-2 text-slate-900" /> {t("reps")} setFieldValues((prev) => ({ ...prev, [`${index}-rep`]: val }))} onBlur={() => { const num = Number(fieldValues[`${index}-rep`] ?? set.repCount); updateSet(index, { repCount: isNaN(num) || num < 1 ? 1 : num }); setFieldValues((prev) => { const next = { ...prev }; delete next[`${index}-rep`]; return next; }); }} placeholder="1" placeholderTextColor="#94a3b8" className="bg-white border border-slate-300 rounded-lg px-3 py-2 text-slate-900" /> {t("restS")} setFieldValues((prev) => ({ ...prev, [`${index}-rest`]: val }))} onBlur={() => { const num = Number(fieldValues[`${index}-rest`] ?? set.restDuration); updateSet(index, { restDuration: isNaN(num) || num < 0 ? 0 : num }); setFieldValues((prev) => { const next = { ...prev }; delete next[`${index}-rest`]; return next; }); }} placeholder="0" placeholderTextColor="#94a3b8" className="bg-white border border-slate-300 rounded-lg px-3 py-2 text-slate-900" /> ))} {t("addSet")} {isSaving ? tc("saving") : t("startSwim")} ); }