fix folder component

This commit is contained in:
2025-06-26 10:29:22 +08:00
parent 33bee642a0
commit bff2a89903
16 changed files with 198 additions and 141 deletions

View File

@@ -0,0 +1,47 @@
// components/Button/Button.tsx
import React from "react";
import { Text, TouchableOpacity } from "react-native";
import buttonStyles from "./buttonStyles";
// Definisi props dengan TypeScript
interface ButtonProps {
onPress: () => void;
title?: string;
backgroundColor?: string;
textColor?: string;
radius?: number;
disabled?: boolean;
iconLeft?: React.ReactNode;
}
const ButtonCustom: React.FC<ButtonProps> = ({
onPress,
title = "Button",
backgroundColor = "#007AFF",
textColor = "#FFFFFF",
radius = 8,
disabled = false,
iconLeft,
}) => {
const styles = buttonStyles({
backgroundColor,
textColor,
borderRadius: radius,
});
return (
<TouchableOpacity
style={[styles.button, disabled && styles.disabled]}
onPress={onPress}
disabled={disabled}
activeOpacity={0.8}
>
{/* Render icon jika tersedia */}
{iconLeft && iconLeft}
<Text style={styles.buttonText}>{title}</Text>
</TouchableOpacity>
);
};
export default ButtonCustom;

View File

@@ -0,0 +1,31 @@
// components/Button/buttonStyles.js
import { MainColor } from "@/constants/color-palet";
import { StyleSheet } from "react-native";
export default function buttonStyles({
backgroundColor = "#007AFF",
textColor = "#FFFFFF",
borderRadius = 8,
}) {
return StyleSheet.create({
button: {
backgroundColor,
paddingVertical: 12,
paddingHorizontal: 20,
borderRadius,
flexDirection: "row", // 👈 Tambahkan baris ini
alignItems: "center",
justifyContent: "center",
gap: 8,
},
buttonText: {
color: textColor,
fontSize: 16,
fontWeight: "600",
},
disabled: {
backgroundColor: MainColor.disabled,
},
});
}

View File

@@ -0,0 +1,100 @@
// components/TextInputCustom.tsx
import Ionicons from "@expo/vector-icons/Ionicons";
import React, { useState } from "react";
import {
TextInput as RNTextInput,
StyleProp,
Text,
TouchableOpacity,
View,
ViewStyle,
} from "react-native";
import { textInputStyles } from "./textInputStyles";
type IconType = React.ReactNode | string;
type Props = {
iconLeft?: IconType;
iconRight?: IconType;
label?: string;
required?: boolean;
error?: string;
secureTextEntry?: boolean;
fontColor?: string;
disabled?: boolean;
borderRadius?: number;
style?: StyleProp<ViewStyle>;
} & Omit<React.ComponentProps<typeof RNTextInput>, "style">;
export const TextInputCustom = ({
iconLeft,
iconRight,
label,
required = false,
error = "",
secureTextEntry = false,
fontColor = "#000",
disabled = false,
borderRadius = 8,
style,
...rest
}: Props) => {
const [isPasswordVisible, setIsPasswordVisible] = useState(false);
// Helper untuk render ikon
const renderIcon = (icon: IconType) => {
if (!icon) return null;
return typeof icon === "string" ? (
<Text style={textInputStyles.iconText}>{icon}</Text>
) : (
icon
);
};
return (
<View style={textInputStyles.container}>
{label && (
<Text style={textInputStyles.label}>
{label}
{required && <Text style={textInputStyles.required}> *</Text>}
</Text>
)}
<View
style={[
textInputStyles.inputContainer,
disabled && textInputStyles.disabled,
{ borderRadius },
error ? textInputStyles.errorBorder : null,
style,
]}
>
{iconLeft && (
<View style={textInputStyles.icon}>{renderIcon(iconLeft)}</View>
)}
<RNTextInput
style={[textInputStyles.input, { color: fontColor }]}
editable={!disabled}
secureTextEntry={secureTextEntry && !isPasswordVisible}
{...rest}
/>
{secureTextEntry && (
<TouchableOpacity
onPress={() => setIsPasswordVisible((prev) => !prev)}
style={textInputStyles.icon}
>
<Ionicons
name={isPasswordVisible ? "eye-off" : "eye"}
size={20}
color="#888"
/>
</TouchableOpacity>
)}
{iconRight && (
<View style={textInputStyles.icon}>{renderIcon(iconRight)}</View>
)}
</View>
{error ? <Text style={textInputStyles.errorMessage}>{error}</Text> : null}
</View>
);
};

View File

@@ -0,0 +1,71 @@
// components/text-input.styles.ts
import { AccentColor, MainColor } from "@/constants/color-palet";
import { StyleSheet } from "react-native";
export const textInputStyles = StyleSheet.create({
// Container utama input (View luar)
container: {
marginBottom: 16,
},
// Label di atas input
label: {
fontSize: 14,
marginBottom: 6,
fontWeight: "500",
color: MainColor.white,
},
// Tanda bintang merah untuk required
required: {
color: "red",
},
// Pesan error di bawah input
errorMessage: {
marginTop: 4,
fontSize: 12,
color: MainColor.red,
},
// Wrapper input (View pembungkus TextInput)
inputContainer: {
flexDirection: "row",
alignItems: "center",
borderWidth: 1,
borderColor: AccentColor.white,
backgroundColor: MainColor.login,
paddingHorizontal: 12,
height: 50,
},
// Style saat disabled
disabled: {
backgroundColor: "#f9f9f9",
borderColor: "#e0e0e0",
},
// Input utama (TextInput)
input: {
flex: 1,
fontSize: 16,
paddingVertical: 0,
},
// Ikon di kiri/kanan
icon: {
marginHorizontal: 4,
justifyContent: "center",
},
// Teks ikon jika berupa string
iconText: {
fontSize: 16,
color: "#000",
},
// Border merah jika ada error
errorBorder: {
borderColor: "red",
},
});

View File

@@ -1,35 +1,43 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { MainColor } from "@/constants/color-palet";
import { globalStyles } from "@/constants/global-styles";
import { Styles } from "@/constants/global-styles";
import { ImageBackground, ScrollView, View } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context";
interface ViewWrapperProps {
children: React.ReactNode;
withBackground?: boolean;
}
const ViewWrapper = ({ children }: ViewWrapperProps) => {
const ViewWrapper = ({
children,
withBackground = false,
}: ViewWrapperProps) => {
const assetBackground = require("../../assets/images/main-background.png");
return (
<SafeAreaView
edges={[]}
style={{
flex: 1,
// paddingTop: StatusBar.currentHeight,
}}
>
<ScrollView contentContainerStyle={{ flexGrow: 1 }} >
<ImageBackground
source={require("../../assets/images/main-background.png")}
resizeMode="cover"
style={globalStyles.imageBackground}
>
<View style={globalStyles.container}>{children}</View>
</ImageBackground>
</ScrollView>
</SafeAreaView>
<SafeAreaProvider>
<SafeAreaView
edges={[]}
style={{
flex: 1,
// paddingTop: StatusBar.currentHeight,
}}
>
<ScrollView contentContainerStyle={{ flexGrow: 1 }}>
{withBackground ? (
<ImageBackground
source={assetBackground}
resizeMode="cover"
style={Styles.imageBackground}
>
<View style={Styles.containerWithBackground}>{children}</View>
</ImageBackground>
) : (
<View style={Styles.container}>{children}</View>
)}
</ScrollView>
</SafeAreaView>
</SafeAreaProvider>
);
};