feature & fix

deskripsi:
- new component : Scroll
- fix : notifikasi, use search, portofolio item drawer
- new constats : padding value
- fix component :
Text custom : tambah warna gray di props
Text Input: tambah props container Style

# No Issue
This commit is contained in:
2025-07-11 17:34:04 +08:00
parent 3301cf3d7a
commit 5183769a7c
10 changed files with 254 additions and 26 deletions

View File

@@ -1,9 +1,118 @@
import { TextCustom, ViewWrapper } from "@/components";
import {
BaseBox,
Grid,
ScrollableCustom,
StackCustom,
TextCustom,
ViewWrapper,
} from "@/components";
import { MainColor } from "@/constants/color-palet";
import { useState } from "react";
import { View } from "react-native";
const categories = [
{ id: 1, label: "Semua" },
{ id: 2, label: "Event" },
{ id: 3, label: "Job" },
{ id: 4, label: "Voting" },
{ id: 5, label: "Donasi" },
{ id: 6, label: "Investasi" },
{ id: 7, label: "Forum" },
{ id: 8, label: "Collaboration" },
];
const selectedCategory = (id: number) => {
const category = categories.find((c) => c.id === id);
return category?.label;
};
const BoxNotification = ({
index,
activeCategory,
}: {
index: number;
activeCategory: number | null;
}) => {
return (
<>
<BaseBox
onPress={() =>
console.log(
"Notification >",
selectedCategory(activeCategory as number)
)
}
>
<StackCustom>
<TextCustom bold>
# {selectedCategory(activeCategory as number)}
</TextCustom>
<View
style={{
borderBottomColor: MainColor.white_gray,
borderBottomWidth: 1,
}}
/>
<TextCustom truncate={2}>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Sint odio
unde quidem voluptate quam culpa sequi molestias ipsa corrupti id,
soluta, nostrum adipisci similique, et illo asperiores deleniti eum
labore.
</TextCustom>
<Grid>
<Grid.Col span={6}>
<TextCustom size="small" color="gray">
{index + 1} Agustus 2025
</TextCustom>
</Grid.Col>
<Grid.Col span={6} style={{ alignItems: "flex-end" }}>
<TextCustom size="small" color="gray">
Belum lihat
</TextCustom>
</Grid.Col>
</Grid>
</StackCustom>
</BaseBox>
</>
);
};
export default function Notifications() {
const [activeCategory, setActiveCategory] = useState<number | null>(1);
const handlePress = (item: any) => {
setActiveCategory(item.id);
// tambahkan logika lain seperti filter dsb.
};
return (
<ViewWrapper>
<TextCustom>Notifications</TextCustom>
<ViewWrapper
headerComponent={
<ScrollableCustom
data={categories}
onButtonPress={handlePress}
activeId={activeCategory as any}
/>
}
>
{Array.from({ length: 20 }).map((e, i) => (
<View key={i}>
<BoxNotification index={i} activeCategory={activeCategory} />
</View>
))}
{/* Konten utama di sini */}
{/* <View style={{ flex: 1 }}>
<Text style={{ color: "white" }}>
{activeCategory
? `Kategori Aktif: ${
categories.find((c) => c.id === activeCategory)?.label
}`
: "Pilih kategori"}
</Text>
</View> */}
</ViewWrapper>
);
}

View File

@@ -52,6 +52,7 @@ export default function UserSearch() {
}
placeholder="Cari Pengguna"
borderRadius={50}
containerStyle={{ marginBottom: 0 }}
/>
}
>

View File

@@ -7,7 +7,7 @@ import { StyleSheet } from "react-native";
export const stylesButton = StyleSheet.create({
button: {
backgroundColor: MainColor.yellow,
paddingVertical: 12,
paddingVertical: 10,
paddingHorizontal: 20,
flexDirection: "row", // 👈 Tambahkan baris ini
alignItems: "center",

View File

@@ -0,0 +1,60 @@
import { AccentColor, MainColor } from "@/constants/color-palet";
import React from "react";
import { ScrollView, StyleSheet } from "react-native";
import ButtonCustom from "../Button/ButtonCustom";
interface ButtonData {
id: string | number;
label: string;
}
interface ScrollableCustomProps {
data: ButtonData[];
onButtonPress: (item: ButtonData) => void;
activeId?: string | number;
}
const ScrollableCustom = ({
data,
onButtonPress,
activeId,
}: ScrollableCustomProps) => {
return (
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={styles.buttonContainer}
style={styles.scrollView}
>
{data.map((item) => {
const isActive = activeId === item.id;
return (
<ButtonCustom
key={item.id}
backgroundColor={isActive ? MainColor.yellow : AccentColor.blue}
textColor={isActive ? MainColor.black : MainColor.white}
onPress={() => onButtonPress(item)}
>
{item.label}
</ButtonCustom>
);
})}
</ScrollView>
);
};
export default ScrollableCustom;
const styles = StyleSheet.create({
scrollView: {
// maxHeight: 50,
},
buttonContainer: {
flexDirection: "row",
alignItems: "center",
// paddingHorizontal: 16,
// paddingVertical: 10,
gap: 12,
},
});

View File

@@ -22,7 +22,7 @@ interface TextCustomProps {
bold?: boolean;
semiBold?: boolean;
size?: "default" | "large" | "small";
color?: "default" | "yellow" | "red";
color?: "default" | "yellow" | "red" | "gray";
align?: TextAlign; // Prop untuk alignment
truncate?: boolean | number;
onPress?: () => void;
@@ -56,6 +56,7 @@ const TextCustom: React.FC<TextCustomProps> = ({
// Color
if (color === "yellow") selectedStyles.push(styles.yellow);
else if (color === "red") selectedStyles.push(styles.red);
else if (color === "gray") selectedStyles.push(styles.gray);
// Alignment
if (align) {
@@ -122,4 +123,7 @@ export const styles = StyleSheet.create({
red: {
color: MainColor.red,
},
gray: {
color: MainColor.placeholder,
},
});

View File

@@ -24,6 +24,7 @@ type Props = {
borderRadius?: number;
style?: StyleProp<ViewStyle>;
maxLength?: number;
containerStyle?: StyleProp<ViewStyle>;
} & Omit<React.ComponentProps<typeof RNTextInput>, "style">;
const TextInputCustom = ({
@@ -40,6 +41,7 @@ const TextInputCustom = ({
keyboardType,
onChangeText,
maxLength,
containerStyle,
...rest
}: Props) => {
const [isPasswordVisible, setIsPasswordVisible] = useState(false);
@@ -73,7 +75,7 @@ const TextInputCustom = ({
};
return (
<View style={GStyles.inputContainerArea}>
<View style={[GStyles.inputContainerArea, containerStyle]}>
{label && (
<Text style={GStyles.inputLabel}>
{label}

View File

@@ -37,6 +37,8 @@ import MapCustom from "./Map/MapCustom";
import CenterCustom from "./Center/CenterCustom";
// Clickable
import ClickableCustom from "./Clickable/ClickableCustom";
// Scroll
import ScrollableCustom from "./Scroll/ScrollCustom";
export {
AlertCustom,
@@ -78,4 +80,6 @@ export {
CenterCustom,
// Clickable
ClickableCustom,
// Scroll
ScrollableCustom,
};

View File

@@ -7,13 +7,31 @@ export {
DRAWER_HEIGHT,
RADIUS_BUTTON,
ICON_SIZE_BUTTON,
PADDING_EXTRA_SMALL,
PADDING_SMALL,
PADDING_MEDIUM,
PADDING_LARGE,
};
// Text Size
const TEXT_SIZE_SMALL = 12;
const TEXT_SIZE_MEDIUM = 14;
const TEXT_SIZE_LARGE = 16;
// Icon Size
const ICON_SIZE_BUTTON = 18
const ICON_SIZE_SMALL = 20;
const ICON_SIZE_MEDIUM = 24;
// Drawer Height
const DRAWER_HEIGHT = 500; // tinggi drawer5
// Radius Button
const RADIUS_BUTTON = 50
const ICON_SIZE_BUTTON = 18
// Padding
const PADDING_EXTRA_SMALL = 10
const PADDING_SMALL = 12
const PADDING_MEDIUM = 16
const PADDING_LARGE = 20

View File

@@ -1,35 +1,61 @@
import { IMenuDrawerItem } from "@/components/_Interface/types";
import { AccentColor } from "@/constants/color-palet";
import { ICON_SIZE_MEDIUM } from "@/constants/constans-value";
import { Ionicons } from "@expo/vector-icons";
import { Ionicons, FontAwesome5, FontAwesome, Fontisto } from "@expo/vector-icons";
export const drawerItemsPortofolio = ({
id,
}: {
id: string;
}): IMenuDrawerItem[] => [
export const drawerItemsPortofolio = ({ id }: { id: string }): IMenuDrawerItem[] => [
{
icon: <Ionicons name="create" size={ICON_SIZE_MEDIUM} color={AccentColor.white} />,
icon: (
<Ionicons
name="create"
size={ICON_SIZE_MEDIUM}
color={AccentColor.white}
/>
),
label: "Edit portofolio",
path: `/(application)/portofolio/${id}/edit`,
},
{
icon: <Ionicons name="camera" size={ICON_SIZE_MEDIUM} color={AccentColor.white} />,
icon: (
<Ionicons
name="camera"
size={ICON_SIZE_MEDIUM}
color={AccentColor.white}
/>
),
label: "Edit logo ",
path: `/(application)/portofolio/${id}/edit-logo`,
},
{
icon: <Ionicons name="image" size={ICON_SIZE_MEDIUM} color={AccentColor.white} />,
icon: (
<FontAwesome
name="id-card-o"
size={ICON_SIZE_MEDIUM}
color={AccentColor.white}
/>
),
label: "Edit social media ",
path: `/(application)/portofolio/${id}/edit-social-media`,
},
{
icon: <Ionicons name="add-circle" size={ICON_SIZE_MEDIUM} color={AccentColor.white} />,
icon: (
<Fontisto
name="map-marker-alt"
size={ICON_SIZE_MEDIUM}
color={AccentColor.white}
/>
),
label: "Edit Map",
path: `/(application)/maps/${id}/edit`,
},
{
icon: <Ionicons name="create-outline" size={ICON_SIZE_MEDIUM} color={AccentColor.white} />,
icon: (
<FontAwesome5
name="map-pin"
size={ICON_SIZE_MEDIUM}
color={AccentColor.white}
/>
),
label: "Custom Pin Map",
path: `/(application)/maps/${id}/custom-pin`,
},

View File

@@ -1,4 +1,8 @@
import {
PADDING_EXTRA_SMALL,
PADDING_LARGE,
PADDING_MEDIUM,
PADDING_SMALL,
TEXT_SIZE_LARGE,
TEXT_SIZE_MEDIUM,
TEXT_SIZE_SMALL,
@@ -12,28 +16,28 @@ export const GStyles = StyleSheet.create({
// =============== Main Styles =============== //
container: {
flex: 1,
paddingInline: 20,
paddingBlock: 10,
paddingInline: PADDING_LARGE,
paddingBlock: PADDING_EXTRA_SMALL,
backgroundColor: MainColor.darkblue,
},
containerWithBackground: {
flex: 1,
paddingInline: 20,
paddingBlock: 10,
paddingInline: PADDING_LARGE,
paddingBlock: PADDING_EXTRA_SMALL,
},
imageBackground: {
height: "100%",
width: "100%",
},
stickyHeader: {
position: "absolute",
position: "relative",
top: 0,
left: 0,
right: 0,
zIndex: 10,
backgroundColor: MainColor.darkblue,
paddingTop: 16,
paddingInline: 16,
backgroundColor: "transparent",
paddingBlock: PADDING_SMALL,
paddingInline: PADDING_MEDIUM,
// padding: 16,
// paddingTop: 8,
// paddingBottom: 8,