diff --git a/src/components/ui/AppText.tsx b/src/components/ui/AppText.tsx index 4eacf0a..563a7c6 100644 --- a/src/components/ui/AppText.tsx +++ b/src/components/ui/AppText.tsx @@ -1,12 +1,17 @@ import React from "react"; -import { Text, type TextProps, type TextStyle } from "react-native"; +import { + Text, + type StyleProp, + type TextProps, + type TextStyle, +} from "react-native"; import { Theme } from "../../theme/theme"; type Variant = "logo" | "title" | "body" | "muted" | "error"; type Props = TextProps & { variant?: Variant; - style?: TextStyle | TextStyle[]; + style?: StyleProp; }; export default function AppText({ variant = "body", style, ...props }: Props) { diff --git a/src/components/ui/Button.tsx b/src/components/ui/Button.tsx index 634afcb..d9021a3 100644 --- a/src/components/ui/Button.tsx +++ b/src/components/ui/Button.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { Pressable, type PressableProps, StyleSheet, View } from "react-native"; +import { Pressable, type PressableProps, StyleSheet } from "react-native"; import { Theme } from "../../theme/theme"; import AppText from "./AppText"; @@ -12,6 +12,7 @@ export default function Button({ title, variant = "primary", style, + disabled, ...props }: Props) { const isPrimary = variant === "primary"; @@ -19,42 +20,42 @@ export default function Button({ return ( [ styles.base, isPrimary ? styles.primary : styles.secondary, - pressed && + + // pressed 스타일(비활성화면 적용 안 함) + !disabled && + pressed && (isPrimary ? styles.primaryPressed : styles.secondaryPressed), + + // disabled 스타일 + disabled && styles.disabled, + typeof style === "function" ? style({ pressed }) : style, ]} > - - - {title} - - + + {title} + ); } const styles = StyleSheet.create({ base: { - height: 48, - paddingVertical: 0, - paddingHorizontal: Theme.Spacing.lg, + paddingVertical: Theme.Spacing.md, borderRadius: Theme.Radius.md, - alignItems: "center", // 가로 가운데 - justifyContent: "center", // 세로 가운데 - }, - text: { - textAlign: "center", - fontWeight: Theme.FontWeight.bold, - lineHeight: 20, + alignItems: "center", + justifyContent: "center", + minHeight: 48, }, primary: { backgroundColor: Theme.Colors.primary, @@ -70,4 +71,22 @@ const styles = StyleSheet.create({ secondaryPressed: { opacity: 0.9, }, + + disabled: { + opacity: 0.5, + }, + + text: { + textAlign: "center", + fontWeight: Theme.FontWeight.bold, + }, + textPrimary: { + color: Theme.Colors.text, + }, + textSecondary: { + color: Theme.Colors.text, + }, + textDisabled: { + color: Theme.Colors.mutedText, + }, }); diff --git a/src/navigation/AuthStack.tsx b/src/navigation/AuthStack.tsx index 49c671d..fd38061 100644 --- a/src/navigation/AuthStack.tsx +++ b/src/navigation/AuthStack.tsx @@ -1,9 +1,11 @@ import { createNativeStackNavigator } from "@react-navigation/native-stack"; import React from "react"; import LoginScreen from "../screens/LoginScreen"; +import SignUpScreen from "../screens/SignUpScreen"; export type AuthStackParamList = { Login: undefined; + SignUp: undefined; }; const Stack = createNativeStackNavigator(); @@ -12,6 +14,10 @@ export default function AuthStack() { return ( + + + + ); } diff --git a/src/screens/HomeScreen.tsx b/src/screens/HomeScreen.tsx index e3ef1b1..0c8427a 100644 --- a/src/screens/HomeScreen.tsx +++ b/src/screens/HomeScreen.tsx @@ -1,7 +1,9 @@ import AsyncStorage from "@react-native-async-storage/async-storage"; import { Button, StyleSheet, View } from "react-native"; +import { useAuth } from "../store/auth"; export default function HomeScreen() { + const { signOut } = useAuth(); return ( ); } diff --git a/src/screens/LoginScreen.tsx b/src/screens/LoginScreen.tsx index ab09e32..b5912f7 100644 --- a/src/screens/LoginScreen.tsx +++ b/src/screens/LoginScreen.tsx @@ -1,9 +1,12 @@ +import { useNavigation } from "@react-navigation/native"; +import { NativeStackNavigationProp } from "@react-navigation/native-stack"; import React, { useState } from "react"; import { Pressable, StyleSheet, View } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; import AppText from "../components/ui/AppText"; import Button from "../components/ui/Button"; import Input from "../components/ui/Input"; +import { AuthStackParamList } from "../navigation/AuthStack"; import { useAuth } from "../store/auth"; import { Theme } from "../theme/theme"; @@ -12,6 +15,8 @@ export default function LoginScreen() { const [loginId, setLoginId] = useState(""); const [password, setPassword] = useState(""); const canSubmit = loginId.trim().length > 0 && password.length > 0; + const navigation = + useNavigation>(); return ( @@ -60,7 +65,7 @@ export default function LoginScreen() { { - console.log("feawf"); + navigation.navigate("SignUp"); }} > diff --git a/src/screens/SignUpScreen.tsx b/src/screens/SignUpScreen.tsx new file mode 100644 index 0000000..fe705c9 --- /dev/null +++ b/src/screens/SignUpScreen.tsx @@ -0,0 +1,121 @@ +import { useNavigation } from "@react-navigation/native"; +import React, { useMemo, useState } from "react"; +import { StyleSheet, View } from "react-native"; +import { SafeAreaView } from "react-native-safe-area-context"; +import AppText from "../components/ui/AppText"; +import Button from "../components/ui/Button"; +import Input from "../components/ui/Input"; +import { Theme } from "../theme/theme"; + +export default function SignUpScreen() { + const navigation = useNavigation(); + + const [loginId, setLoginId] = useState(""); + const [password, setPassword] = useState(""); + const [passwordConfirm, setPasswordConfirm] = useState(""); + + const { canSubmit, errorText } = useMemo(() => { + const idOk = loginId.trim().length >= 4; + const pwOk = password.length >= 8; + const match = password.length > 0 && password === passwordConfirm; + + const can = idOk && pwOk && match; + + let err = ""; + if (loginId.length > 0 && !idOk) + err = "Username must be at least 4 characters."; + else if (password.length > 0 && !pwOk) + err = "Password must be at least 8 characters."; + else if (passwordConfirm.length > 0 && !match) + err = "Passwords do not match."; + + return { canSubmit: can, errorText: err }; + }, [loginId, password, passwordConfirm]); + + const onSignUp = async () => { + navigation.goBack(); + }; + + return ( + + + Create your account + Start listening in minutes + + + + + + + + + + + + { + if (canSubmit) onSignUp(); + }} + /> + + {errorText ? ( + + {errorText} + + ) : null} + + + +