feature
deskripsi: - portofolio: detail bisnis, maps, media social - new component divide # No Issue
This commit is contained in:
@@ -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 */}
|
||||
|
||||
186
components/Divider/DividerCustom.tsx
Normal file
186
components/Divider/DividerCustom.tsx
Normal 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;
|
||||
@@ -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",
|
||||
|
||||
11
screens/Portofolio/BusinessLocationSection.tsx
Normal file
11
screens/Portofolio/BusinessLocationSection.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import { BaseBox, TextCustom } from "@/components";
|
||||
|
||||
export default function Portofolio_BusinessLocation() {
|
||||
return (
|
||||
<>
|
||||
<BaseBox>
|
||||
<TextCustom bold>Lokasi Bisnis</TextCustom>
|
||||
</BaseBox>
|
||||
</>
|
||||
);
|
||||
}
|
||||
14
screens/Portofolio/ButtonDelete.tsx
Normal file
14
screens/Portofolio/ButtonDelete.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
154
screens/Portofolio/DataPortofolio.tsx
Normal file
154
screens/Portofolio/DataPortofolio.tsx
Normal 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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
17
screens/Portofolio/PorfofolioSection.tsx
Normal file
17
screens/Portofolio/PorfofolioSection.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
79
screens/Portofolio/SocialMediaSection.tsx
Normal file
79
screens/Portofolio/SocialMediaSection.tsx
Normal 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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user