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:
@@ -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() {
|
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 (
|
return (
|
||||||
<ViewWrapper>
|
<ViewWrapper
|
||||||
<TextCustom>Notifications</TextCustom>
|
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>
|
</ViewWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ export default function UserSearch() {
|
|||||||
}
|
}
|
||||||
placeholder="Cari Pengguna"
|
placeholder="Cari Pengguna"
|
||||||
borderRadius={50}
|
borderRadius={50}
|
||||||
|
containerStyle={{ marginBottom: 0 }}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { StyleSheet } from "react-native";
|
|||||||
export const stylesButton = StyleSheet.create({
|
export const stylesButton = StyleSheet.create({
|
||||||
button: {
|
button: {
|
||||||
backgroundColor: MainColor.yellow,
|
backgroundColor: MainColor.yellow,
|
||||||
paddingVertical: 12,
|
paddingVertical: 10,
|
||||||
paddingHorizontal: 20,
|
paddingHorizontal: 20,
|
||||||
flexDirection: "row", // 👈 Tambahkan baris ini
|
flexDirection: "row", // 👈 Tambahkan baris ini
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
|
|||||||
60
components/Scroll/ScrollCustom.tsx
Normal file
60
components/Scroll/ScrollCustom.tsx
Normal 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,
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -22,7 +22,7 @@ interface TextCustomProps {
|
|||||||
bold?: boolean;
|
bold?: boolean;
|
||||||
semiBold?: boolean;
|
semiBold?: boolean;
|
||||||
size?: "default" | "large" | "small";
|
size?: "default" | "large" | "small";
|
||||||
color?: "default" | "yellow" | "red";
|
color?: "default" | "yellow" | "red" | "gray";
|
||||||
align?: TextAlign; // Prop untuk alignment
|
align?: TextAlign; // Prop untuk alignment
|
||||||
truncate?: boolean | number;
|
truncate?: boolean | number;
|
||||||
onPress?: () => void;
|
onPress?: () => void;
|
||||||
@@ -56,6 +56,7 @@ const TextCustom: React.FC<TextCustomProps> = ({
|
|||||||
// Color
|
// Color
|
||||||
if (color === "yellow") selectedStyles.push(styles.yellow);
|
if (color === "yellow") selectedStyles.push(styles.yellow);
|
||||||
else if (color === "red") selectedStyles.push(styles.red);
|
else if (color === "red") selectedStyles.push(styles.red);
|
||||||
|
else if (color === "gray") selectedStyles.push(styles.gray);
|
||||||
|
|
||||||
// Alignment
|
// Alignment
|
||||||
if (align) {
|
if (align) {
|
||||||
@@ -122,4 +123,7 @@ export const styles = StyleSheet.create({
|
|||||||
red: {
|
red: {
|
||||||
color: MainColor.red,
|
color: MainColor.red,
|
||||||
},
|
},
|
||||||
|
gray: {
|
||||||
|
color: MainColor.placeholder,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ type Props = {
|
|||||||
borderRadius?: number;
|
borderRadius?: number;
|
||||||
style?: StyleProp<ViewStyle>;
|
style?: StyleProp<ViewStyle>;
|
||||||
maxLength?: number;
|
maxLength?: number;
|
||||||
|
containerStyle?: StyleProp<ViewStyle>;
|
||||||
} & Omit<React.ComponentProps<typeof RNTextInput>, "style">;
|
} & Omit<React.ComponentProps<typeof RNTextInput>, "style">;
|
||||||
|
|
||||||
const TextInputCustom = ({
|
const TextInputCustom = ({
|
||||||
@@ -40,6 +41,7 @@ const TextInputCustom = ({
|
|||||||
keyboardType,
|
keyboardType,
|
||||||
onChangeText,
|
onChangeText,
|
||||||
maxLength,
|
maxLength,
|
||||||
|
containerStyle,
|
||||||
...rest
|
...rest
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const [isPasswordVisible, setIsPasswordVisible] = useState(false);
|
const [isPasswordVisible, setIsPasswordVisible] = useState(false);
|
||||||
@@ -73,7 +75,7 @@ const TextInputCustom = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={GStyles.inputContainerArea}>
|
<View style={[GStyles.inputContainerArea, containerStyle]}>
|
||||||
{label && (
|
{label && (
|
||||||
<Text style={GStyles.inputLabel}>
|
<Text style={GStyles.inputLabel}>
|
||||||
{label}
|
{label}
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ import MapCustom from "./Map/MapCustom";
|
|||||||
import CenterCustom from "./Center/CenterCustom";
|
import CenterCustom from "./Center/CenterCustom";
|
||||||
// Clickable
|
// Clickable
|
||||||
import ClickableCustom from "./Clickable/ClickableCustom";
|
import ClickableCustom from "./Clickable/ClickableCustom";
|
||||||
|
// Scroll
|
||||||
|
import ScrollableCustom from "./Scroll/ScrollCustom";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
AlertCustom,
|
AlertCustom,
|
||||||
@@ -78,4 +80,6 @@ export {
|
|||||||
CenterCustom,
|
CenterCustom,
|
||||||
// Clickable
|
// Clickable
|
||||||
ClickableCustom,
|
ClickableCustom,
|
||||||
|
// Scroll
|
||||||
|
ScrollableCustom,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,13 +7,31 @@ export {
|
|||||||
DRAWER_HEIGHT,
|
DRAWER_HEIGHT,
|
||||||
RADIUS_BUTTON,
|
RADIUS_BUTTON,
|
||||||
ICON_SIZE_BUTTON,
|
ICON_SIZE_BUTTON,
|
||||||
|
PADDING_EXTRA_SMALL,
|
||||||
|
PADDING_SMALL,
|
||||||
|
PADDING_MEDIUM,
|
||||||
|
PADDING_LARGE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Text Size
|
||||||
const TEXT_SIZE_SMALL = 12;
|
const TEXT_SIZE_SMALL = 12;
|
||||||
const TEXT_SIZE_MEDIUM = 14;
|
const TEXT_SIZE_MEDIUM = 14;
|
||||||
const TEXT_SIZE_LARGE = 16;
|
const TEXT_SIZE_LARGE = 16;
|
||||||
|
|
||||||
|
// Icon Size
|
||||||
|
const ICON_SIZE_BUTTON = 18
|
||||||
const ICON_SIZE_SMALL = 20;
|
const ICON_SIZE_SMALL = 20;
|
||||||
const ICON_SIZE_MEDIUM = 24;
|
const ICON_SIZE_MEDIUM = 24;
|
||||||
|
|
||||||
|
// Drawer Height
|
||||||
const DRAWER_HEIGHT = 500; // tinggi drawer5
|
const DRAWER_HEIGHT = 500; // tinggi drawer5
|
||||||
|
|
||||||
|
// Radius Button
|
||||||
const RADIUS_BUTTON = 50
|
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
|
||||||
|
|
||||||
|
|||||||
@@ -1,35 +1,61 @@
|
|||||||
import { IMenuDrawerItem } from "@/components/_Interface/types";
|
import { IMenuDrawerItem } from "@/components/_Interface/types";
|
||||||
import { AccentColor } from "@/constants/color-palet";
|
import { AccentColor } from "@/constants/color-palet";
|
||||||
import { ICON_SIZE_MEDIUM } from "@/constants/constans-value";
|
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 = ({
|
export const drawerItemsPortofolio = ({ id }: { id: string }): IMenuDrawerItem[] => [
|
||||||
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",
|
label: "Edit portofolio",
|
||||||
path: `/(application)/portofolio/${id}/edit`,
|
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 ",
|
label: "Edit logo ",
|
||||||
path: `/(application)/portofolio/${id}/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 ",
|
label: "Edit social media ",
|
||||||
path: `/(application)/portofolio/${id}/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",
|
label: "Edit Map",
|
||||||
path: `/(application)/maps/${id}/edit`,
|
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",
|
label: "Custom Pin Map",
|
||||||
path: `/(application)/maps/${id}/custom-pin`,
|
path: `/(application)/maps/${id}/custom-pin`,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
|
PADDING_EXTRA_SMALL,
|
||||||
|
PADDING_LARGE,
|
||||||
|
PADDING_MEDIUM,
|
||||||
|
PADDING_SMALL,
|
||||||
TEXT_SIZE_LARGE,
|
TEXT_SIZE_LARGE,
|
||||||
TEXT_SIZE_MEDIUM,
|
TEXT_SIZE_MEDIUM,
|
||||||
TEXT_SIZE_SMALL,
|
TEXT_SIZE_SMALL,
|
||||||
@@ -12,28 +16,28 @@ export const GStyles = StyleSheet.create({
|
|||||||
// =============== Main Styles =============== //
|
// =============== Main Styles =============== //
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
paddingInline: 20,
|
paddingInline: PADDING_LARGE,
|
||||||
paddingBlock: 10,
|
paddingBlock: PADDING_EXTRA_SMALL,
|
||||||
backgroundColor: MainColor.darkblue,
|
backgroundColor: MainColor.darkblue,
|
||||||
},
|
},
|
||||||
containerWithBackground: {
|
containerWithBackground: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
paddingInline: 20,
|
paddingInline: PADDING_LARGE,
|
||||||
paddingBlock: 10,
|
paddingBlock: PADDING_EXTRA_SMALL,
|
||||||
},
|
},
|
||||||
imageBackground: {
|
imageBackground: {
|
||||||
height: "100%",
|
height: "100%",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
},
|
},
|
||||||
stickyHeader: {
|
stickyHeader: {
|
||||||
position: "absolute",
|
position: "relative",
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
zIndex: 10,
|
zIndex: 10,
|
||||||
backgroundColor: MainColor.darkblue,
|
backgroundColor: "transparent",
|
||||||
paddingTop: 16,
|
paddingBlock: PADDING_SMALL,
|
||||||
paddingInline: 16,
|
paddingInline: PADDING_MEDIUM,
|
||||||
// padding: 16,
|
// padding: 16,
|
||||||
// paddingTop: 8,
|
// paddingTop: 8,
|
||||||
// paddingBottom: 8,
|
// paddingBottom: 8,
|
||||||
|
|||||||
Reference in New Issue
Block a user