deskripsi:
- portofolio: detail bisnis, maps, media social
- new component divide
# No Issue
This commit is contained in:
2025-07-10 11:58:23 +08:00
parent 71ea0ca5f2
commit 862af44c03
8 changed files with 485 additions and 21 deletions

View File

@@ -4,14 +4,12 @@ import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
import { MainColor } from "@/constants/color-palet";
import { drawerItemsPortofolio } from "@/screens/Portofolio/ListPage";
import Portofolio_MenuDrawerSection from "@/screens/Portofolio/MenuDrawer";
import PorfofolioSection from "@/screens/Portofolio/PorfofolioSection";
import { GStyles } from "@/styles/global-styles";
import { Ionicons } from "@expo/vector-icons";
import { Stack, useLocalSearchParams } from "expo-router";
import { useState } from "react";
import {
Text,
TouchableOpacity
} from "react-native";
import { TouchableOpacity } from "react-native";
export default function Portofolio() {
const { id } = useLocalSearchParams();
@@ -44,7 +42,7 @@ export default function Portofolio() {
headerTitleStyle: GStyles.headerTitleStyle,
}}
/>
<Text style={GStyles.textLabel}>Portofolio {id}</Text>
<PorfofolioSection />
</ViewWrapper>
{/* Drawer Komponen Eksternal */}

View File

@@ -0,0 +1,186 @@
import React from "react";
import {
View,
Text,
StyleSheet,
StyleProp,
ViewStyle,
TextStyle,
} from "react-native";
// Define types for props
type Orientation = "horizontal" | "vertical";
type HorizontalLabelPosition = "center" | "left" | "right";
type VerticalLabelPosition = "center" | "top" | "bottom";
type LabelPosition = HorizontalLabelPosition | VerticalLabelPosition;
type Size = number | "xs" | "sm" | "md" | "lg" | "xl";
interface DividerProps {
orientation?: Orientation;
color?: string;
size?: Size;
label?: React.ReactNode;
labelPosition?: LabelPosition;
labelStyle?: StyleProp<TextStyle>;
style?: StyleProp<ViewStyle>;
}
const Divider: React.FC<DividerProps> = ({
orientation = "horizontal",
color = "#DADADA",
size = "xs",
label,
labelPosition = "center",
labelStyle,
style,
}) => {
const isHorizontal = orientation === "horizontal";
// Convert size to actual dimensions
const getSize = (): number => {
if (typeof size === "number") return size;
switch (size) {
case "xs":
return 1;
case "sm":
return 2;
case "md":
return 3;
case "lg":
return 4;
case "xl":
return 5;
default:
return 1; // Default size
}
};
const thickness = getSize();
const capitalize = (str: string): string =>
str.charAt(0).toUpperCase() + str.slice(1);
const renderLabel = () => {
if (!label) return null;
return (
<View
style={[
styles.labelContainer,
isHorizontal
? styles[
`label${capitalize(
labelPosition as string
)}` as keyof typeof styles
]
: styles[
`label${capitalize(
labelPosition as string
)}` as keyof typeof styles
],
]}
>
<Text style={[styles.labelText, labelStyle]}>{label}</Text>
</View>
);
};
return (
<View
style={[
isHorizontal ? styles.horizontalDivider : styles.verticalDivider,
{ backgroundColor: color },
style,
]}
>
{isHorizontal ? (
labelPosition !== "center" ? (
<View style={{ flex: 1, flexDirection: "row", alignItems: "center" }}>
{labelPosition === "left" && renderLabel()}
<View
style={{ flex: 1, backgroundColor: color, height: thickness }}
/>
{labelPosition === "right" && renderLabel()}
</View>
) : (
<>
{renderLabel()}
<View style={{ flex: 1 }} />
</>
)
) : labelPosition !== "center" && !isHorizontal ? (
<View
style={{ flex: 1, flexDirection: "column", justifyContent: "center" }}
>
{labelPosition === "top" && renderLabel()}
<View style={{ flex: 1, backgroundColor: color, width: thickness }} />
{labelPosition === "bottom" && renderLabel()}
</View>
) : (
<>
{renderLabel()}
<View style={{ flex: 1 }} />
</>
)}
</View>
);
};
const styles = StyleSheet.create({
horizontalDivider: {
flexDirection: "row",
alignItems: "center",
marginVertical: 8,
position: "relative",
},
verticalDivider: {
flexDirection: "column",
justifyContent: "center",
marginHorizontal: 8,
position: "relative",
},
labelText: {
fontSize: 14,
fontWeight: "500",
color: "#666",
marginHorizontal: 12,
marginVertical: 4,
backgroundColor: "white",
paddingHorizontal: 8,
},
labelContainer: {
position: "absolute",
left: 0,
right: 0,
justifyContent: "center",
alignItems: "center",
},
labelLeft: {
left: 12,
right: null,
alignItems: "flex-start",
},
labelRight: {
right: 12,
left: null,
alignItems: "flex-end",
},
labelCenter: {
justifyContent: "center",
alignItems: "center",
},
labelTop: {
top: 12,
bottom: null,
justifyContent: "flex-start",
},
labelBottom: {
bottom: 12,
top: null,
justifyContent: "flex-end",
},
});
export default Divider;

View File

@@ -5,7 +5,13 @@ import {
TEXT_SIZE_SMALL,
} from "@/constants/constans-value";
import React from "react";
import { Text as RNText, StyleProp, StyleSheet, TextStyle, TouchableOpacity } from "react-native";
import {
Text as RNText,
StyleProp,
StyleSheet,
TextStyle,
TouchableOpacity,
} from "react-native";
// Tambahkan type TextAlignProps agar lebih type-safe
type TextAlign = "left" | "center" | "right";
@@ -62,20 +68,8 @@ const TextCustom: React.FC<TextCustomProps> = ({
return selectedStyles;
};
return (
onPress ? (
<TouchableOpacity onPress={onPress}>
<RNText
numberOfLines={
typeof truncate === "number" ? truncate : truncate ? 1 : undefined
}
ellipsizeMode="tail"
style={getStyle()}
>
{children}
</RNText>
</TouchableOpacity>
) : (
return onPress ? (
<TouchableOpacity onPress={onPress}>
<RNText
numberOfLines={
typeof truncate === "number" ? truncate : truncate ? 1 : undefined
@@ -85,7 +79,17 @@ const TextCustom: React.FC<TextCustomProps> = ({
>
{children}
</RNText>
)
</TouchableOpacity>
) : (
<RNText
numberOfLines={
typeof truncate === "number" ? truncate : truncate ? 1 : undefined
}
ellipsizeMode="tail"
style={getStyle()}
>
{children}
</RNText>
);
};
@@ -96,6 +100,7 @@ export const styles = StyleSheet.create({
fontSize: TEXT_SIZE_MEDIUM,
color: MainColor.white,
fontFamily: "Poppins-Regular",
lineHeight: 20,
},
bold: {
fontFamily: "Poppins-Bold",

View File

@@ -0,0 +1,11 @@
import { BaseBox, TextCustom } from "@/components";
export default function Portofolio_BusinessLocation() {
return (
<>
<BaseBox>
<TextCustom bold>Lokasi Bisnis</TextCustom>
</BaseBox>
</>
);
}

View File

@@ -0,0 +1,14 @@
import { ButtonCustom } from "@/components";
import { MainColor } from "@/constants/color-palet";
import { Ionicons } from "@expo/vector-icons";
export default function Portofolio_ButtonDelete() {
const handleDelete = () => {
console.log("Delete");
};
return (
<ButtonCustom textColor={MainColor.white} iconLeft={<Ionicons name="trash-outline" size={20} color="white" />} onPress={handleDelete} backgroundColor={MainColor.red}>
Hapus
</ButtonCustom>
);
}

View File

@@ -0,0 +1,154 @@
import {
AvatarCustom,
BaseBox,
Grid,
StackCustom,
TextCustom,
} from "@/components";
import DividerCustom from "@/components/Divider/DividerCustom";
import { AccentColor } from "@/constants/color-palet";
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
import { FontAwesome, Ionicons } from "@expo/vector-icons";
import { useLocalSearchParams } from "expo-router";
import { View } from "react-native";
export default function Portofolio_Data() {
const { id } = useLocalSearchParams();
const listData = [
{
icon: (
<FontAwesome name="building-o" size={ICON_SIZE_SMALL} color="white" />
),
label: "PT.Bali Interakrtif Perkasa",
},
{
icon: (
<Ionicons name="call-outline" size={ICON_SIZE_SMALL} color="white" />
),
label: "+6282340374412",
},
{
icon: (
<Ionicons name="home-outline" size={ICON_SIZE_SMALL} color="white" />
),
label: "Jl. Raya Kuta No. 123, Bandung, Indonesia",
},
{
icon: (
<Ionicons name="list-outline" size={ICON_SIZE_SMALL} color="white" />
),
label: "Teknologia",
},
];
const listSubBidang = [
{
icon: (
<Ionicons
name="chevron-forward-outline"
size={ICON_SIZE_SMALL}
color="white"
/>
),
label: "Security System",
},
{
icon: (
<Ionicons
name="chevron-forward-outline"
size={ICON_SIZE_SMALL}
color="white"
/>
),
label: "Web Developers",
},
{
icon: (
<Ionicons
name="chevron-forward-outline"
size={ICON_SIZE_SMALL}
color="white"
/>
),
label: "Mobile Developers",
},
];
return (
<>
<BaseBox>
<StackCustom>
<Grid>
<Grid.Col span={6}>
<TextCustom bold>Data Bisnis</TextCustom>
</Grid.Col>
<Grid.Col span={6} style={{ alignItems: "flex-end" }}>
<TextCustom color="yellow">ID: {id}</TextCustom>
</Grid.Col>
</Grid>
<View style={{ alignItems: "center" }}>
<AvatarCustom size="xl" />
</View>
{/* <Spacing height={10}/> */}
<View>
{listData.map((item, index) => (
<Grid key={index}>
<Grid.Col span={2} style={{ alignItems: "center" }}>
{item.icon}
</Grid.Col>
<Grid.Col span={10}>
<TextCustom style={{ paddingLeft: 5 }}>
{item.label}
</TextCustom>
</Grid.Col>
</Grid>
))}
<View style={{ paddingLeft: 10 }}>
{listSubBidang.map((item, index) => (
<Grid key={index}>
<Grid.Col span={2} style={{ alignItems: "center" }}>
{item.icon}
</Grid.Col>
<Grid.Col span={10}>
<TextCustom style={{ paddingLeft: 5 }}>
{item.label}
</TextCustom>
</Grid.Col>
</Grid>
))}
</View>
</View>
<DividerCustom labelPosition="top" color={AccentColor.blue} />
<View>
<Grid>
<Grid.Col span={2} style={{ alignItems: "center" }}>
<Ionicons
name="pin-outline"
size={ICON_SIZE_SMALL}
color="white"
/>
</Grid.Col>
<Grid.Col span={10}>
<TextCustom bold style={{ paddingLeft: 5 }}>
Tentang Kami
</TextCustom>
</Grid.Col>
</Grid>
<TextCustom style={{ paddingInline: 10 }}>
Lorem ipsum, dolor sit amet consectetur adipisicing elit.
Doloremque, alias perspiciatis quis enim eos facilis sit est?
Doloremque, rerum. Cumque error asperiores harum temporibus
cupiditate ullam, id quibusdam! Harum, rerum!
</TextCustom>
</View>
</StackCustom>
</BaseBox>
</>
);
}

View File

@@ -0,0 +1,17 @@
import { Spacing, StackCustom } from "@/components";
import Portofolio_BusinessLocation from "./BusinessLocationSection";
import Portofolio_Data from "./DataPortofolio";
import Portofolio_SocialMediaSection from "./SocialMediaSection";
import Portofolio_ButtonDelete from "./ButtonDelete";
export default function PorfofolioSection() {
return (
<StackCustom>
<Portofolio_Data />
<Portofolio_BusinessLocation />
<Portofolio_SocialMediaSection />
<Portofolio_ButtonDelete/>
<Spacing/>
</StackCustom>
);
}

View File

@@ -0,0 +1,79 @@
import { BaseBox, Grid, StackCustom, TextCustom } from "@/components";
import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
import { Ionicons } from "@expo/vector-icons";
import { View } from "react-native";
export default function Portofolio_SocialMediaSection() {
const listData = [
{
label: "Facebook ku bagas",
icon: (
<Ionicons
name="logo-facebook"
size={ICON_SIZE_SMALL}
color={MainColor.white}
/>
),
},
{
label: "Tiktok ku bagas",
icon: (
<Ionicons
name="logo-tiktok"
size={ICON_SIZE_SMALL}
color={MainColor.white}
/>
),
},
{
label: "Instagram ku bagas",
icon: (
<Ionicons
name="logo-instagram"
size={ICON_SIZE_SMALL}
color={MainColor.white}
/>
),
},
{
label: "Twitter ku bagas",
icon: (
<Ionicons
name="logo-twitter"
size={ICON_SIZE_SMALL}
color={MainColor.white}
/>
),
},
{
label: "Youtube ku bagas",
icon: (
<Ionicons
name="logo-youtube"
size={ICON_SIZE_SMALL}
color={MainColor.white}
/>
),
},
];
return (
<>
<BaseBox>
<StackCustom>
<TextCustom bold>Media Sosial Bisnis</TextCustom>
{listData.map((item, index) => (
<Grid key={index}>
<Grid.Col span={2} style={{ alignItems: "center" }}>
{item.icon}
</Grid.Col>
<Grid.Col span={10} style={{ paddingLeft: 5 }}>
<TextCustom>{item.label}</TextCustom>
</Grid.Col>
</Grid>
))}
</StackCustom>
</BaseBox>
</>
);
}