Compare commits

...

7 Commits

Author SHA1 Message Date
71ea0ca5f2 feature & fix
deskripsi:
- perubahan komponen drawer
- penambahan list page drawer portofolio
- new file portofolio: edit, edit logo, edit sosmed
- new file maps: edit, custom-pin
#No Issue
2025-07-10 10:27:30 +08:00
ee7efaef6a fix & featur
deskripsi:
- fix component stack dan drawer
- new page list path profile
2025-07-09 17:22:43 +08:00
bfb029058c feature
deskripsi:
- new page daftar portofolio
2025-07-09 15:29:04 +08:00
b7e774a556 fix
deskripsi:
- perubahan pada component: ButtonCustom, TextArea, TextInput
- fix style global
- tambhan color pada palet
2025-07-09 15:03:41 +08:00
2901d19db0 fix
deksripsi:
- fix Text input exported
2025-07-09 11:52:38 +08:00
5c4dadbe7c fix
dekripsi:
- fix styles Select
2025-07-09 11:40:22 +08:00
6ac122c631 styles
deskripsi:
- fix styles Text input & Text area
2025-07-09 10:58:47 +08:00
36 changed files with 780 additions and 453 deletions

View File

@@ -1,6 +1,6 @@
{
"expo": {
"name": "hipmi-mobile",
"name": "HIPMI BADUNG",
"slug": "hipmi-mobile",
"version": "1.0.0",
"orientation": "portrait",

View File

@@ -32,7 +32,7 @@ export default function UserLayout() {
}}
/>
{/* Profile */}
{/* ========== Profile Section ========= */}
<Stack.Screen
name="profile"
options={{
@@ -40,15 +40,15 @@ export default function UserLayout() {
}}
/>
{/* Portofolio */}
{/* ========== Portofolio Section ========= */}
<Stack.Screen
name="portofolio"
options={{
headerShown: false,
}}
/>
{/* User Search */}
{/* ========== User Search Section ========= */}
<Stack.Screen
name="user-search/index"
options={{
@@ -57,7 +57,7 @@ export default function UserLayout() {
}}
/>
{/* Notification */}
{/* ========== Notification Section ========= */}
<Stack.Screen
name="notifications/index"
options={{
@@ -66,7 +66,7 @@ export default function UserLayout() {
}}
/>
{/* Event */}
{/* ========== Event Section ========= */}
<Stack.Screen
name="event/(tabs)"
options={{
@@ -85,7 +85,7 @@ export default function UserLayout() {
}}
/>
{/* Forum */}
{/* ========== Forum Section ========= */}
<Stack.Screen
name="forum/index"
options={{
@@ -94,7 +94,7 @@ export default function UserLayout() {
}}
/>
{/* Maps */}
{/* ========== Maps Section ========= */}
<Stack.Screen
name="maps/index"
options={{
@@ -102,8 +102,29 @@ export default function UserLayout() {
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen
name="maps/create"
options={{
title: "Tambah Maps",
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen
name="maps/[id]/edit"
options={{
title: "Edit Maps",
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen
name="maps/[id]/custom-pin"
options={{
title: "Custom Pin Maps",
headerLeft: () => <BackButton />,
}}
/>
{/* Marketplace */}
{/* ========== Marketplace Section ========= */}
<Stack.Screen
name="marketplace/index"
options={{

View File

@@ -0,0 +1,11 @@
import { TextCustom, ViewWrapper } from "@/components";
export default function MapsCustomPin() {
return (
<>
<ViewWrapper>
<TextCustom>Maps Custom Pin</TextCustom>
</ViewWrapper>
</>
);
}

View File

@@ -0,0 +1,11 @@
import { TextCustom, ViewWrapper } from "@/components";
export default function MapsEdit() {
return (
<>
<ViewWrapper>
<TextCustom>Maps Edit</TextCustom>
</ViewWrapper>
</>
);
}

View File

@@ -0,0 +1,59 @@
import {
BaseBox,
BoxButtonOnFooter,
ButtonCenteredOnly,
ButtonCustom,
InformationBox,
LandscapeFrameUploaded,
Spacing,
TextCustom,
TextInputCustom,
ViewWrapper,
} from "@/components";
import { router, useLocalSearchParams } from "expo-router";
export default function MapsCreate() {
const { id } = useLocalSearchParams();
const buttonFooter = (
<BoxButtonOnFooter>
<ButtonCustom
onPress={() => {
console.log("Simpan");
router.replace(`/portofolio/${id}`);
}}
>
Simpan
</ButtonCustom>
</BoxButtonOnFooter>
);
return (
<ViewWrapper footerComponent={buttonFooter}>
<InformationBox text="Tentukan lokasi pin map dengan menekan pada map." />
<BaseBox style={{ height: 400 }}>
<TextCustom>Maps Her</TextCustom>
</BaseBox>
<TextInputCustom
required
label="Nama Pin"
placeholder="Masukkan nama pin maps"
/>
<Spacing height={50} />
<InformationBox text="Upload foto lokasi bisnis anda untuk ditampilkan dalam detail maps." />
<LandscapeFrameUploaded />
<ButtonCenteredOnly
icon="upload"
onPress={() => {
console.log("Upload foto ");
router.navigate(`/take-picture/${id}`);
}}
>
Upload
</ButtonCenteredOnly>
<Spacing height={50} />
</ViewWrapper>
);
}

View File

@@ -1,7 +1,10 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import {
BoxButtonOnFooter,
ButtonCenteredOnly,
ButtonCustom,
Grid,
InformationBox,
LandscapeFrameUploaded,
SelectCustom,
Spacing,
StackCustom,
@@ -10,15 +13,11 @@ import {
TextInputCustom,
ViewWrapper,
} from "@/components";
import BoxButtonOnFooter from "@/components/Box/BoxButtonOnFooter";
import InformationBox from "@/components/Box/InformationBox";
import ButtonCenteredOnly from "@/components/Button/ButtonCenteredOnly";
import LandscapeFrameUploaded from "@/components/Image/LandscapeFrameUploaded";
import { MainColor } from "@/constants/color-palet";
import dummyMasterBidangBisnis from "@/lib/dummy-data/master-bidang-bisnis";
import dummyMasterSubBidangBisnis from "@/lib/dummy-data/master-sub-bidang-bisnis";
import { Ionicons } from "@expo/vector-icons";
import { useLocalSearchParams } from "expo-router";
import { router, useLocalSearchParams } from "expo-router";
import { useState } from "react";
import { Text, TouchableOpacity, View } from "react-native";
import PhoneInput, { ICountry } from "react-native-international-phone-number";
@@ -45,7 +44,8 @@ export default function PortofolioCreate() {
}
function handleSave() {
console.log("save");
console.log("Selanjutnya");
router.replace(`/maps/create`);
}
const buttonSave = (
@@ -57,12 +57,13 @@ export default function PortofolioCreate() {
return (
<ViewWrapper footerComponent={buttonSave}>
{/* <TextCustom>Portofolio Create {id}</TextCustom> */}
<StackCustom>
<StackCustom gap={"xs"}>
<InformationBox text="Lengkapi data bisnis anda." />
<TextInputCustom
required
label="Nama Bisnis"
placeholder="Masukkan nama bisnis"
/>
<SelectCustom
label="Bidang Usaha"
@@ -71,20 +72,26 @@ export default function PortofolioCreate() {
label: item.name,
value: item.id,
}))}
value=""
onChange={(value) => console.log(value)}
value={data.bidang_usaha}
onChange={(value) => {
setData({ ...(data as any), bidang_usaha: value });
}}
/>
<Grid>
<Grid.Col span={10}>
<SelectCustom
// disabled
label="Sub Bidang Usaha"
required
data={dummyMasterSubBidangBisnis.map((item) => ({
label: item.name,
value: item.id,
}))}
value=""
onChange={(value) => console.log(value)}
value={data.sub_bidang_usaha}
onChange={(value) => {
setData({ ...(data as any), sub_bidang_usaha: value });
}}
/>
</Grid.Col>
<Grid.Col
@@ -96,15 +103,12 @@ export default function PortofolioCreate() {
</TouchableOpacity>
</Grid.Col>
</Grid>
<ButtonCenteredOnly onPress={() => console.log("add")}>
Tambah Pilihan
</ButtonCenteredOnly>
<Spacing />
<TextInputCustom
required
label="Alamat Bisnis"
placeholder="Masukkan alamat bisnis"
/>
<View>
<View style={{ flexDirection: "row", alignItems: "center" }}>
<TextCustom semiBold style={{ color: MainColor.white_gray }}>
@@ -123,6 +127,13 @@ export default function PortofolioCreate() {
/>
</View>
<Spacing />
<TextInputCustom
required
label="Alamat Bisnis"
placeholder="Masukkan alamat bisnis"
/>
<TextAreaCustom
label="Deskripsi Bisnis"
placeholder="Masukkan deskripsi bisnis"
@@ -136,12 +147,22 @@ export default function PortofolioCreate() {
maxLength={100}
/>
<Spacing />
{/* Logo */}
<InformationBox text="Upload logo bisnis anda untuk di tampilaka pada portofolio." />
<LandscapeFrameUploaded />
<ButtonCenteredOnly icon="upload" onPress={() => console.log("upload")}>
<ButtonCenteredOnly
icon="upload"
onPress={() => {
console.log("Upload logo >>", id);
router.navigate(`/(application)/take-picture/${id}`);
}}
>
Upload
</ButtonCenteredOnly>
<Spacing height={40} />
{/* Social Media */}
<InformationBox text="Isi hanya pada sosial media yang anda miliki." />
<TextInputCustom
label="Tiktok"

View File

@@ -0,0 +1,11 @@
import { TextCustom, ViewWrapper } from "@/components";
export default function PortofolioEditLogo() {
return (
<>
<ViewWrapper>
<TextCustom>Portofolio Edit Logo</TextCustom>
</ViewWrapper>
</>
);
}

View File

@@ -0,0 +1,11 @@
import { TextCustom, ViewWrapper } from "@/components";
export default function PortofolioEditSocialMedia() {
return (
<>
<ViewWrapper>
<TextCustom>Portofolio Edit Social Media</TextCustom>
</ViewWrapper>
</>
);
}

View File

@@ -0,0 +1,11 @@
import { TextCustom, ViewWrapper } from "@/components";
export default function PortofolioEdit() {
return (
<>
<ViewWrapper>
<TextCustom>Portofolio Edit</TextCustom>
</ViewWrapper>
</>
);
}

View File

@@ -1,32 +1,63 @@
import { DrawerCustom } from "@/components";
import LeftButtonCustom from "@/components/Button/BackButton";
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 { GStyles } from "@/styles/global-styles";
import { Ionicons } from "@expo/vector-icons";
import { Stack, useLocalSearchParams } from "expo-router";
import { Text } from "react-native";
import { useState } from "react";
import {
Text,
TouchableOpacity
} from "react-native";
export default function Portofolio() {
const { id } = useLocalSearchParams();
const { id } = useLocalSearchParams();
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
const openDrawer = () => {
setIsDrawerOpen(true);
};
const closeDrawer = () => {
setIsDrawerOpen(false);
};
return (
<ViewWrapper>
{/* Header */}
<Stack.Screen
options={{
title: "Portofolio",
headerLeft: () => <LeftButtonCustom />,
// headerRight: () => (
// <TouchableOpacity onPress={openDrawer}>
// <Ionicons
// name="ellipsis-vertical"
// size={20}
// color={MainColor.yellow}
// />
// </TouchableOpacity>
// ),
headerStyle: GStyles.headerStyle,
headerTitleStyle: GStyles.headerTitleStyle,
}}
/>
<Text style={GStyles.textLabel}>Portofolio {id}</Text>
</ViewWrapper>
<>
<ViewWrapper>
{/* Header */}
<Stack.Screen
options={{
title: "Portofolio",
headerLeft: () => <LeftButtonCustom />,
headerRight: () => (
<TouchableOpacity onPress={openDrawer}>
<Ionicons
name="ellipsis-vertical"
size={20}
color={MainColor.yellow}
/>
</TouchableOpacity>
),
headerStyle: GStyles.headerStyle,
headerTitleStyle: GStyles.headerTitleStyle,
}}
/>
<Text style={GStyles.textLabel}>Portofolio {id}</Text>
</ViewWrapper>
{/* Drawer Komponen Eksternal */}
<DrawerCustom
isVisible={isDrawerOpen}
closeDrawer={closeDrawer}
height={350}
>
<Portofolio_MenuDrawerSection
drawerItems={drawerItemsPortofolio({ id: id as string })}
setIsDrawerOpen={setIsDrawerOpen}
/>
</DrawerCustom>
</>
);
}

View File

@@ -0,0 +1,47 @@
import { BaseBox, Grid, TextCustom, ViewWrapper } from "@/components";
import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
import { Ionicons } from "@expo/vector-icons";
import { router, useLocalSearchParams } from "expo-router";
export default function ListPortofolio() {
const { id } = useLocalSearchParams();
return (
<ViewWrapper>
{Array.from({ length: 10 }).map((_, index) => (
<BaseBox
key={index}
style={{ backgroundColor: MainColor.darkblue }}
onPress={() => {
console.log("press to Portofolio");
router.push(`/portofolio/${id}`);
}}
>
<Grid>
<Grid.Col
span={10}
style={{ justifyContent: "center", backgroundColor: "" }}
>
<TextCustom bold size="large" truncate={1}>
Nama usaha portofolio
</TextCustom>
<TextCustom size="small" color="yellow">
#id-porofolio12345
</TextCustom>
</Grid.Col>
<Grid.Col
span={2}
style={{ alignItems: "flex-end", justifyContent: "center" }}
>
<Ionicons
name="caret-forward"
size={ICON_SIZE_SMALL}
color="white"
/>
</Grid.Col>
</Grid>
</BaseBox>
))}
</ViewWrapper>
);
}

View File

@@ -1,6 +1,5 @@
import LeftButtonCustom from "@/components/Button/BackButton";
import { GStyles } from "@/styles/global-styles";
import { HeaderStyles } from "@/styles/header-styles";
import { Stack } from "expo-router";
export default function PortofolioLayout() {
@@ -8,10 +7,7 @@ export default function PortofolioLayout() {
<>
<Stack
screenOptions={{
headerStyle: GStyles.headerStyle,
headerTitleStyle: GStyles.headerTitleStyle,
headerTitleAlign: "center",
headerBackButtonDisplayMode: "minimal",
...HeaderStyles,
headerLeft: () => <LeftButtonCustom />,
}}
>
@@ -20,7 +16,16 @@ export default function PortofolioLayout() {
name="[id]/create"
options={{ title: "Tambah Portofolio" }}
/>
<Stack.Screen
name="[id]/list"
options={{ title: "Daftar Portofolio" }}
/>
<Stack.Screen name="[id]/edit" options={{ title: "Edit Portofolio" }} />
<Stack.Screen name="[id]/edit-logo" options={{ title: "Edit Logo " }} />
<Stack.Screen
name="[id]/edit-social-media"
options={{ title: "Edit Social Media" }}
/>
</Stack>
</>
);

View File

@@ -1,5 +1,6 @@
import {
AvatarCustom,
ButtonCenteredOnly,
ButtonCustom,
SelectCustom,
Spacing,
@@ -9,7 +10,6 @@ import {
} from "@/components";
import BoxButtonOnFooter from "@/components/Box/BoxButtonOnFooter";
import InformationBox from "@/components/Box/InformationBox";
import ButtonUpload from "@/components/Button/ButtonUpload";
import LandscapeFrameUploaded from "@/components/Image/LandscapeFrameUploaded";
import { router, useLocalSearchParams } from "expo-router";
import { useState } from "react";
@@ -47,9 +47,12 @@ export default function CreateProfile() {
<View style={{ alignItems: "center" }}>
<AvatarCustom size="xl" />
<Spacing />
<ButtonUpload
<ButtonCenteredOnly
icon="upload"
onPress={() => router.navigate(`/take-picture/${id}`)}
/>
>
Upload
</ButtonCenteredOnly>
</View>
<Spacing />
@@ -58,9 +61,12 @@ export default function CreateProfile() {
<InformationBox text="Upload foto latar belakang anda." />
<LandscapeFrameUploaded />
<Spacing />
<ButtonUpload
<ButtonCenteredOnly
icon="upload"
onPress={() => router.navigate(`/take-picture/${id}`)}
/>
>
Upload
</ButtonCenteredOnly>
</View>
<Spacing />

View File

@@ -1,79 +1,28 @@
import { IMenuDrawerItem } from "@/components/_Interface/types";
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
import AlertCustom from "@/components/Alert/AlertCustom";
import LeftButtonCustom from "@/components/Button/BackButton";
import DrawerCustom from "@/components/Drawer/DrawerCustom";
import { MainColor } from "@/constants/color-palet";
import { DRAWER_HEIGHT } from "@/constants/constans-value";
import { drawerItemsProfile } from "@/screens/Profile/ListPage";
import Profile_MenuDrawerSection from "@/screens/Profile/MenuDrawerSection";
import ProfilSection from "@/screens/Profile/ProfilSection";
import { GStyles } from "@/styles/global-styles";
import { Ionicons } from "@expo/vector-icons";
import { router, Stack, useLocalSearchParams } from "expo-router";
import React, { useRef, useState } from "react";
import { Animated, InteractionManager, TouchableOpacity } from "react-native";
import React, { useState } from "react";
import { TouchableOpacity } from "react-native";
export default function Profile() {
const { id } = useLocalSearchParams();
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
const [showLogoutAlert, setShowLogoutAlert] = useState(false);
const drawerItems: IMenuDrawerItem[] = [
{
icon: "create",
label: "Edit profile",
path: `/(application)/profile/${id}/edit`,
},
{
icon: "camera",
label: "Ubah foto profile",
path: `/(application)/profile/${id}/update-photo`,
},
{
icon: "image",
label: "Ubah latar belakang",
path: `/(application)/profile/${id}/update-background`,
},
{
icon: "add-circle",
label: "Tambah portofolio",
path: `/(application)/portofolio/${id}/create`,
},
// {
// icon: "settings",
// label: "Dashboard Admin",
// path: `/(application)/profile/dashboard-admin`,
// },
{ icon: "log-out", label: "Keluar", color: "red", path: "" },
{
icon: "create-outline",
label: "Create profile",
path: `/(application)/profile/${id}/create`,
},
];
// Animasi menggunakan translateY (lebih kompatibel)
const drawerAnim = useRef(new Animated.Value(DRAWER_HEIGHT)).current; // mulai di luar bawah layar
const openDrawer = () => {
setIsDrawerOpen(true);
Animated.timing(drawerAnim, {
toValue: 0,
duration: 300,
useNativeDriver: true,
}).start();
};
const closeDrawer = () => {
Animated.timing(drawerAnim, {
toValue: DRAWER_HEIGHT, // sesuaikan dengan tinggi drawer Anda
duration: 300,
useNativeDriver: true,
}).start(() => {
InteractionManager.runAfterInteractions(() => {
setIsDrawerOpen(false); // baru ganti state setelah animasi selesai
});
});
setIsDrawerOpen(false);
};
const handleLogout = () => {
@@ -104,18 +53,16 @@ export default function Profile() {
}}
/>
<ProfilSection />
</ViewWrapper>
{/* Drawer Komponen Eksternal */}
<DrawerCustom
height={350}
isVisible={isDrawerOpen}
drawerAnim={drawerAnim}
closeDrawer={closeDrawer}
>
<Profile_MenuDrawerSection
drawerItems={drawerItems}
drawerItems={drawerItemsProfile({ id: id as string })}
setShowLogoutAlert={setShowLogoutAlert}
setIsDrawerOpen={setIsDrawerOpen}
/>

View File

@@ -1,25 +1,31 @@
import { BaseBox, ButtonCustom } from "@/components";
import {
BaseBox,
BoxButtonOnFooter,
ButtonCenteredOnly,
ButtonCustom,
} from "@/components";
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
import ButtonUpload from "@/components/Button/ButtonUpload";
import DUMMY_IMAGE from "@/constants/dummy-image-value";
import { router, useLocalSearchParams } from "expo-router";
import { Image } from "react-native";
export default function UpdateBackgroundProfile() {
const { id } = useLocalSearchParams();
const buttonFooter = (
<BoxButtonOnFooter>
<ButtonCustom
onPress={() => {
console.log("Simpan foto background >>", id);
router.back();
}}
>
Simpan
</ButtonCustom>
</BoxButtonOnFooter>
);
return (
<ViewWrapper
bottomBarComponent={
<ButtonCustom
onPress={() => {
console.log("Simpan foto background >>", id);
router.back();
}}
>
Simpan
</ButtonCustom>
}
>
<ViewWrapper footerComponent={buttonFooter}>
<BaseBox
style={{ alignItems: "center", justifyContent: "center", height: 250 }}
>
@@ -30,12 +36,12 @@ export default function UpdateBackgroundProfile() {
/>
</BaseBox>
<ButtonUpload
title="Update"
onPress={() =>
router.navigate(`/(application)/take-picture/${id}`)
}
/>
<ButtonCenteredOnly
icon="upload"
onPress={() => router.navigate(`/(application)/take-picture/${id}`)}
>
Update
</ButtonCenteredOnly>
</ViewWrapper>
);
}

View File

@@ -1,25 +1,30 @@
import { BaseBox, ButtonCustom } from "@/components";
import {
BaseBox,
BoxButtonOnFooter,
ButtonCenteredOnly,
ButtonCustom,
} from "@/components";
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
import ButtonUpload from "@/components/Button/ButtonUpload";
import DUMMY_IMAGE from "@/constants/dummy-image-value";
import { router, useLocalSearchParams } from "expo-router";
import { Image } from "react-native";
export default function UpdatePhotoProfile() {
const { id } = useLocalSearchParams();
const buttonFooter = (
<BoxButtonOnFooter>
<ButtonCustom
onPress={() => {
console.log("Simpan foto profile >>", id);
router.back();
}}
>
Simpan
</ButtonCustom>
</BoxButtonOnFooter>
);
return (
<ViewWrapper
bottomBarComponent={
<ButtonCustom
onPress={() => {
console.log("Simpan foto profile >>", id);
router.back();
}}
>
Simpan
</ButtonCustom>
}
>
<ViewWrapper footerComponent={buttonFooter}>
<BaseBox
style={{ alignItems: "center", justifyContent: "center", height: 250 }}
>
@@ -30,13 +35,18 @@ export default function UpdatePhotoProfile() {
/>
</BaseBox>
<ButtonUpload
title="Update"
<ButtonCenteredOnly
icon="upload"
onPress={() => {
console.log("Update photo >>", id);
router.navigate(`/(application)/take-picture/${id}`);
}}
/>
>
Update
</ButtonCenteredOnly>
{/* <Spacing />
<ButtonCustom>Test</ButtonCustom> */}
</ViewWrapper>
);
}

View File

@@ -67,7 +67,7 @@ export default function TakePicture() {
/>
<Spacing />
<StackCustom>
<StackCustom >
<ButtonCustom onPress={() => setUri(null)} title="Foto ulang" />
<ButtonCustom
onPress={() => {

View File

@@ -2,13 +2,12 @@
import React from "react";
import { StyleProp, Text, TouchableOpacity, ViewStyle } from "react-native";
import buttonStyles from "./buttonCustomStyles";
import { radiusMap } from "@/constants/radius-value";
import { MainColor } from "@/constants/color-palet";
import { stylesButton } from "./buttonCustomStyles";
// Import radiusMap
// Definisi type untuk radius
type RadiusType = keyof typeof radiusMap | number;
@@ -30,30 +29,29 @@ const ButtonCustom: React.FC<ButtonProps> = ({
title = "Button",
backgroundColor = MainColor.yellow,
textColor = MainColor.black,
radius = "full", // default md
radius = 50, // default md
disabled = false,
iconLeft,
style,
}) => {
const borderRadius =
typeof radius === "number" ? radius : radiusMap[radius ?? "md"]; // fallback ke 'md'
const styles = buttonStyles({
backgroundColor,
textColor,
borderRadius,
});
return (
<TouchableOpacity
style={[styles.button, disabled && styles.disabled, style]}
style={[
stylesButton.button,
disabled && stylesButton.disabled,
style,
{ borderRadius: radius },
{ backgroundColor },
]}
onPress={onPress}
disabled={disabled}
activeOpacity={0.8}
>
{/* Render icon jika tersedia */}
{iconLeft && iconLeft}
<Text style={styles.buttonText}>{children || title}</Text>
<Text style={[stylesButton.buttonText, { color: textColor }]}>
{children || title}
</Text>
</TouchableOpacity>
);
};

View File

@@ -1,21 +0,0 @@
import { MainColor } from "@/constants/color-palet";
import { GStyles } from "@/styles/global-styles";
import { Feather } from "@expo/vector-icons";
import React from "react";
import ButtonCustom from "./ButtonCustom";
interface ButtonUploadProps {
title?: string;
onPress: () => void;
}
export default function ButtonUpload({ onPress, title = "Upload" }: ButtonUploadProps) {
return (
<ButtonCustom
onPress={onPress}
iconLeft={<Feather name="upload" size={20} color={MainColor.black} />}
style={GStyles.buttonCentered50Percent}
>
{title}
</ButtonCustom>
);
}

View File

@@ -4,24 +4,18 @@ import { MainColor } from "@/constants/color-palet";
import { TEXT_SIZE_MEDIUM } from "@/constants/constans-value";
import { StyleSheet } from "react-native";
export default function buttonStyles({
backgroundColor = "#007AFF",
textColor = "#FFFFFF",
borderRadius = 8,
}) {
return StyleSheet.create({
export const stylesButton = StyleSheet.create({
button: {
backgroundColor,
backgroundColor: MainColor.yellow,
paddingVertical: 12,
paddingHorizontal: 20,
borderRadius,
flexDirection: "row", // 👈 Tambahkan baris ini
alignItems: "center",
justifyContent: "center",
gap: 8,
},
buttonText: {
color: textColor,
color: MainColor.black,
fontSize: TEXT_SIZE_MEDIUM,
fontWeight: "600",
},
@@ -29,4 +23,3 @@ export default function buttonStyles({
backgroundColor: MainColor.disabled,
},
});
}

View File

@@ -1,10 +1,10 @@
import React, { useRef } from "react";
import React, { useEffect, useRef } from "react";
import {
Animated,
InteractionManager,
PanResponder,
StyleSheet,
View,
Animated,
PanResponder,
StyleSheet,
View,
InteractionManager,
} from "react-native";
import { AccentColor, MainColor } from "@/constants/color-palet";
@@ -14,7 +14,7 @@ interface DrawerCustomProps {
children?: React.ReactNode;
height?: number;
isVisible: boolean;
drawerAnim: Animated.Value;
drawerAnim?: Animated.Value;
closeDrawer: () => void;
// openLogoutAlert: () => void;
}
@@ -33,6 +33,26 @@ export default function DrawerCustom({
closeDrawer,
}: // openLogoutAlert,
DrawerCustomProps) {
const drawerAnima = useRef(
new Animated.Value(height || DRAWER_HEIGHT)
).current;
// Efek untuk handle open/close drawer
useEffect(() => {
if (isVisible) {
Animated.timing(drawerAnima, {
toValue: 0,
duration: 300,
useNativeDriver: true,
}).start();
} else {
Animated.timing(drawerAnima, {
toValue: height || DRAWER_HEIGHT,
duration: 300,
useNativeDriver: true,
}).start();
}
}, [isVisible, drawerAnim, height, closeDrawer, drawerAnima]);
const panResponder = useRef(
PanResponder.create({
onMoveShouldSetPanResponder: (_, gestureState) => {
@@ -41,7 +61,7 @@ DrawerCustomProps) {
onPanResponderMove: (_, gestureState) => {
const offset = gestureState.dy;
if (offset >= 0 && offset <= DRAWER_HEIGHT) {
drawerAnim.setValue(offset);
drawerAnima.setValue(offset);
}
},
onPanResponderRelease: (_, gestureState) => {
@@ -50,7 +70,7 @@ DrawerCustomProps) {
closeDrawer();
});
} else {
Animated.spring(drawerAnim, {
Animated.spring(drawerAnima, {
toValue: 0,
useNativeDriver: true,
}).start();
@@ -80,13 +100,13 @@ DrawerCustomProps) {
styles.drawer,
{
height: height || DRAWER_HEIGHT,
transform: [{ translateY: drawerAnim }],
transform: [{ translateY: drawerAnima }],
},
]}
{...panResponder.panHandlers}
>
<View
style={[styles.headerBar, { backgroundColor: MainColor.white_gray }]}
style={[styles.headerBar, { backgroundColor: MainColor.white }]}
/>
{children}
@@ -152,7 +172,7 @@ const styles = StyleSheet.create({
headerBar: {
width: 40,
height: 5,
backgroundColor: MainColor.white_gray,
backgroundColor: MainColor.white,
borderRadius: 5,
alignSelf: "center",
marginVertical: 10,

View File

@@ -1,12 +1,10 @@
// components/Select.tsx
import { MainColor } from "@/constants/color-palet";
import { TEXT_SIZE_MEDIUM } from "@/constants/constans-value";
import { GStyles } from "@/styles/global-styles";
import React, { useState } from "react";
import {
FlatList,
Modal,
Pressable,
StyleSheet,
Text,
TouchableOpacity,
View,
@@ -23,7 +21,9 @@ type SelectProps = {
data: SelectItem[];
value?: string | number | null;
required?: boolean; // <-- new prop
disabled?: boolean; // <-- tambahkan prop disabled
onChange: (value: string | number) => void;
borderRadius?: number;
};
const SelectCustom: React.FC<SelectProps> = ({
@@ -32,7 +32,9 @@ const SelectCustom: React.FC<SelectProps> = ({
data,
value,
required = false, // <-- default false
disabled = false, // <-- default false
onChange,
borderRadius = 8,
}) => {
const [modalVisible, setModalVisible] = useState(false);
@@ -41,35 +43,50 @@ const SelectCustom: React.FC<SelectProps> = ({
const hasError = required && value === null; // <-- check if empty and required
return (
<View style={styles.container}>
<View style={GStyles.inputContainerArea}>
{label && (
<Text style={styles.label}>
<Text style={GStyles.inputLabel}>
{label}
{required && <Text style={styles.requiredIndicator}> *</Text>}
{required && <Text style={GStyles.inputRequired}> *</Text>}
</Text>
)}
<Pressable
style={[styles.input, hasError ? styles.inputError : null]} // <-- add error style
onPress={() => setModalVisible(true)}
style={[
{ borderRadius },
hasError ? GStyles.inputErrorBorder : null,
GStyles.inputContainerInput,
disabled && GStyles.disabledBox,
]} // <-- add error style
onPress={() => !disabled && setModalVisible(true)}
>
<Text style={selectedItem ? styles.text : styles.placeholder}>
<Text
style={
selectedItem
? disabled
? GStyles.inputTextDisabled
: GStyles.inputText
: disabled
? GStyles.inputPlaceholderDisabled
: GStyles.inputPlaceholder
}
>
{selectedItem?.label || placeholder}
</Text>
</Pressable>
<Modal visible={modalVisible} transparent animationType="fade">
<TouchableOpacity
style={styles.modalOverlay}
style={GStyles.selectModalOverlay}
activeOpacity={1}
onPressOut={() => setModalVisible(false)}
>
<View style={styles.modalContent}>
<View style={GStyles.selectModalContent}>
<FlatList
data={data}
keyExtractor={(item) => String(item.value)}
renderItem={({ item }) => (
<TouchableOpacity
style={styles.option}
style={GStyles.selectOption}
onPress={() => {
onChange(item.value);
setModalVisible(false);
@@ -85,68 +102,10 @@ const SelectCustom: React.FC<SelectProps> = ({
{/* Optional Error Message */}
{hasError && (
<Text style={styles.errorMessage}>Harap pilih salah satu</Text>
<Text style={GStyles.inputErrorMessage}>Harap pilih salah satu</Text>
)}
</View>
);
};
export default SelectCustom;
const styles = StyleSheet.create({
container: {
marginBottom: 16,
},
label: {
fontSize: TEXT_SIZE_MEDIUM,
marginBottom: 4,
color: MainColor.white_gray,
fontWeight: "500",
},
requiredIndicator: {
color: "red",
fontWeight: "bold",
},
input: {
borderWidth: 1,
borderColor: MainColor.white_gray,
padding: 12,
borderRadius: 8,
minHeight: 48,
justifyContent: "center",
backgroundColor: MainColor.white,
},
inputError: {
borderColor: "red",
},
text: {
fontSize: TEXT_SIZE_MEDIUM,
},
placeholder: {
fontSize: TEXT_SIZE_MEDIUM,
color: MainColor.placeholder,
},
modalOverlay: {
flex: 1,
backgroundColor: "rgba(0,0,0,0.3)",
justifyContent: "center",
alignItems: "center",
},
modalContent: {
width: "80%",
maxHeight: 300,
backgroundColor: "white",
borderRadius: 8,
overflow: "hidden",
},
option: {
padding: 16,
borderBottomWidth: 1,
borderBottomColor: "#eee",
},
errorMessage: {
marginTop: 4,
fontSize: 12,
color: "red",
},
});

View File

@@ -19,7 +19,7 @@ const StackCustom: React.FC<StackProps> = ({
children,
align = "stretch",
justify = "flex-start",
gap = "xs",
gap = "md",
direction = "column",
style,
}) => {

View File

@@ -5,7 +5,7 @@ import {
TEXT_SIZE_SMALL,
} from "@/constants/constans-value";
import React from "react";
import { Text as RNText, StyleProp, StyleSheet, TextStyle } 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";
@@ -19,6 +19,7 @@ interface TextCustomProps {
color?: "default" | "yellow" | "red";
align?: TextAlign; // Prop untuk alignment
truncate?: boolean | number;
onPress?: () => void;
}
const TextCustom: React.FC<TextCustomProps> = ({
@@ -30,6 +31,7 @@ const TextCustom: React.FC<TextCustomProps> = ({
color = "default",
align = "left", // Default alignment
truncate = false,
onPress,
}) => {
const getStyle = () => {
let selectedStyles = [];
@@ -61,15 +63,29 @@ const TextCustom: React.FC<TextCustomProps> = ({
};
return (
<RNText
numberOfLines={
typeof truncate === "number" ? truncate : truncate ? 1 : undefined
}
ellipsizeMode="tail"
style={getStyle()}
>
{children}
</RNText>
onPress ? (
<TouchableOpacity onPress={onPress}>
<RNText
numberOfLines={
typeof truncate === "number" ? truncate : truncate ? 1 : undefined
}
ellipsizeMode="tail"
style={getStyle()}
>
{children}
</RNText>
</TouchableOpacity>
) : (
<RNText
numberOfLines={
typeof truncate === "number" ? truncate : truncate ? 1 : undefined
}
ellipsizeMode="tail"
style={getStyle()}
>
{children}
</RNText>
)
);
};

View File

@@ -1,14 +1,13 @@
import { GStyles } from "@/styles/global-styles";
import React, { useEffect, useState } from "react";
import {
TextInput as RNTextInput,
StyleProp,
Text,
View,
ViewStyle,
TextInput as RNTextInput,
StyleProp,
Text,
View,
ViewStyle,
} from "react-native";
import { textInputStyles } from "../TextInput/textInputStyles";
type IconType = React.ReactNode | string;
type BaseProps = {
@@ -71,31 +70,31 @@ const TextAreaCustom: React.FC<TextAreaCustomProps> = ({
const renderIcon = (icon: IconType) => {
if (!icon) return null;
return typeof icon === "string" ? (
<Text style={textInputStyles.iconText}>{icon}</Text>
<Text style={GStyles.inputIconText}>{icon}</Text>
) : (
icon
);
};
return (
<View style={textInputStyles.container}>
<View style={GStyles.inputContainerArea}>
{label && (
<Text style={textInputStyles.label}>
<Text style={GStyles.inputLabel}>
{label}
{required && <Text style={textInputStyles.required}> *</Text>}
{required && <Text style={GStyles.inputRequired}> *</Text>}
</Text>
)}
<View
style={[
textInputStyles.inputContainer,
disabled && textInputStyles.disabled,
hasError ? textInputStyles.errorBorder : {},
GStyles.inputContainerInput,
disabled && GStyles.disabledBox,
hasError ? GStyles.inputErrorBorder : {},
{ borderRadius },
style,
]}
>
{iconLeft && (
<View style={textInputStyles.icon}>{renderIcon(iconLeft)}</View>
<View style={GStyles.inputIcon}>{renderIcon(iconLeft)}</View>
)}
<RNTextInput
@@ -103,8 +102,8 @@ const TextAreaCustom: React.FC<TextAreaCustomProps> = ({
multiline
numberOfLines={numberOfLines}
style={[
textInputStyles.input,
textInputStyles.textArea,
GStyles.inputText,
GStyles.textAreaInput,
{ color: fontColor },
]}
editable={!disabled}
@@ -114,7 +113,7 @@ const TextAreaCustom: React.FC<TextAreaCustomProps> = ({
/>
{iconRight && (
<View style={textInputStyles.icon}>{renderIcon(iconRight)}</View>
<View style={GStyles.inputIcon}>{renderIcon(iconRight)}</View>
)}
</View>
@@ -128,11 +127,11 @@ const TextAreaCustom: React.FC<TextAreaCustomProps> = ({
}}
>
{hasError ? (
<Text style={textInputStyles.errorMessage}>{error}</Text>
<Text style={GStyles.inputErrorMessage}>{error}</Text>
) : null}
{showCount && maxLength ? (
<Text style={textInputStyles.inputLength}>
<Text style={GStyles.inputMaxLength}>
{(value as string)?.length || 0}/{maxLength}
</Text>
) : null}

View File

@@ -1,3 +1,4 @@
import { GStyles } from "@/styles/global-styles";
import Ionicons from "@expo/vector-icons/Ionicons";
import React, { useState } from "react";
import {
@@ -8,7 +9,6 @@ import {
View,
ViewStyle,
} from "react-native";
import { textInputStyles } from "./textInputStyles";
type IconType = React.ReactNode | string;
@@ -26,7 +26,7 @@ type Props = {
maxLength?: number;
} & Omit<React.ComponentProps<typeof RNTextInput>, "style">;
export const TextInputCustom = ({
const TextInputCustom = ({
iconLeft,
iconRight,
label,
@@ -49,7 +49,7 @@ export const TextInputCustom = ({
const renderIcon = (icon: IconType) => {
if (!icon) return null;
return typeof icon === "string" ? (
<Text style={textInputStyles.iconText}>{icon}</Text>
<Text style={GStyles.inputIconText}>{icon}</Text>
) : (
icon
);
@@ -73,27 +73,31 @@ export const TextInputCustom = ({
};
return (
<View style={textInputStyles.container}>
<View style={GStyles.inputContainerArea}>
{label && (
<Text style={textInputStyles.label}>
<Text style={GStyles.inputLabel}>
{label}
{required && <Text style={textInputStyles.required}> *</Text>}
{required && <Text style={GStyles.inputRequired}> *</Text>}
</Text>
)}
<View
style={[
textInputStyles.inputContainer,
disabled && textInputStyles.disabled,
{ borderRadius },
externalError || internalError ? textInputStyles.errorBorder : null,
style,
{ borderRadius },
externalError || internalError ? GStyles.inputErrorBorder : null,
GStyles.inputContainerInput,
disabled && GStyles.disabledBox,
]}
>
{iconLeft && (
<View style={textInputStyles.icon}>{renderIcon(iconLeft)}</View>
)}
{/* {iconLeft && (
<View style={GStyles.inputIcon}>{renderIcon(iconLeft)}</View>
)} */}
<RNTextInput
style={[textInputStyles.input, { color: fontColor }]}
style={[
GStyles.inputText,
{ color: fontColor },
disabled && GStyles.inputPlaceholderDisabled, // <-- placeholder saat disabled
]}
editable={!disabled}
secureTextEntry={secureTextEntry && !isPasswordVisible}
keyboardType={keyboardType}
@@ -104,7 +108,7 @@ export const TextInputCustom = ({
{secureTextEntry && (
<TouchableOpacity
onPress={() => setIsPasswordVisible((prev) => !prev)}
style={textInputStyles.icon}
style={GStyles.inputIcon}
>
<Ionicons
name={isPasswordVisible ? "eye-off" : "eye"}
@@ -114,15 +118,17 @@ export const TextInputCustom = ({
</TouchableOpacity>
)}
{iconRight && (
<View style={textInputStyles.icon}>{renderIcon(iconRight)}</View>
<View style={GStyles.inputIcon}>{renderIcon(iconRight)}</View>
)}
</View>
{/* Prioritaskan error eksternal */}
{externalError || internalError ? (
<Text style={textInputStyles.errorMessage}>
<Text style={GStyles.inputErrorMessage}>
{externalError || internalError}
</Text>
) : null}
</View>
);
};
export default TextInputCustom;

View File

@@ -1,3 +0,0 @@
import { TextInputCustom } from "./TextInputCustom";
export { TextInputCustom };

View File

@@ -1,85 +0,0 @@
// components/text-input.styles.ts
import { MainColor } from "@/constants/color-palet";
import { TEXT_SIZE_LARGE, TEXT_SIZE_MEDIUM } from "@/constants/constans-value";
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_gray,
},
// Tanda bintang merah untuk required
required: {
color: "red",
},
// Pesan error di bawah input
errorMessage: {
marginTop: 4,
fontSize: 12,
color: MainColor.red,
},
// Input Length
inputLength: {
fontSize: 12,
color: MainColor.white_gray,
},
// Wrapper input (View pembungkus TextInput)
inputContainer: {
flexDirection: "row",
alignItems: "center",
borderWidth: 1,
borderColor: MainColor.white_gray,
backgroundColor: MainColor.white,
paddingHorizontal: 12,
height: 50,
},
// Style saat disabled
disabled: {
backgroundColor: "#f9f9f9",
borderColor: "#e0e0e0",
},
// Input utama (TextInput)
input: {
flex: 1,
fontSize: TEXT_SIZE_MEDIUM,
paddingVertical: 0,
},
// Ikon di kiri/kanan
icon: {
marginHorizontal: 4,
justifyContent: "center",
},
// Teks ikon jika berupa string
iconText: {
fontSize: TEXT_SIZE_LARGE,
color: "#000",
},
// Border merah jika ada error
errorBorder: {
borderColor: "red",
},
// Untuk TextArea tambahan
textArea: {
textAlignVertical: "top",
padding: 12,
height: undefined, // biar multiline bebas tinggi
},
});

View File

@@ -4,7 +4,6 @@ import AlertCustom from "./Alert/AlertCustom";
import LeftButtonCustom from "./Button/BackButton";
import ButtonCenteredOnly from "./Button/ButtonCenteredOnly";
import ButtonCustom from "./Button/ButtonCustom";
import ButtonUpload from "./Button/ButtonUpload";
// Drawer
import DrawerCustom from "./Drawer/DrawerCustom";
import MenuDrawerDynamicGrid from "./Drawer/MenuDrawerDynamicGird";
@@ -14,32 +13,42 @@ import ViewWrapper from "./_ShareComponent/ViewWrapper";
// Text
import TextCustom from "./Text/TextCustom";
// TextInput
import { TextInputCustom } from "./TextInput/TextInputCustom";
import TextInputCustom from "./TextInput/TextInputCustom";
// TextArea
import TextAreaCustom from "./TextArea/TextAreaCustom";
// Grid
import Grid from "./Grid/GridCustom";
// Box
import BaseBox from "./Box/BaseBox";
// Avatar
import AvatarCustom from "./Image/AvatarCustom";
import BoxButtonOnFooter from "./Box/BoxButtonOnFooter";
import InformationBox from "./Box/InformationBox";
// Stack
import StackCustom from "./Stack/StackCustom";
// Select
import SelectCustom from "./Select/SelectCustom";
// Image
import AvatarCustom from "./Image/AvatarCustom";
import LandscapeFrameUploaded from "./Image/LandscapeFrameUploaded";
export {
AlertCustom,
// Avatar
// Image
AvatarCustom,
LandscapeFrameUploaded,
// Button
ButtonCustom,
LeftButtonCustom as BackButton,
ButtonCenteredOnly,
// Box
BaseBox, ButtonCenteredOnly, ButtonCustom, ButtonUpload,
BaseBox,
BoxButtonOnFooter,
InformationBox,
// Drawer
DrawerCustom,
// Grid
Grid, MenuDrawerDynamicGrid,
Grid,
MenuDrawerDynamicGrid,
// Select
SelectCustom,
// ShareComponent
@@ -53,6 +62,5 @@ export {
// TextInput
TextInputCustom,
// ViewWrapper
ViewWrapper
ViewWrapper,
};

View File

@@ -3,24 +3,27 @@ export const MainColor = {
darkblue: "#001D3D",
soft_darkblue: "#0e3763",
yellow: "#E1B525",
white_gray: "#D4D0D0",
red: "#FF4B4C",
orange: "#FF7043",
green: "#4CAF4F",
white_gray: "#D4D0D0",
text_input: "#EDEBEBFF",
placeholder: "#999",
disabled: "#606360",
placeholder: "#888",
white: "#ffffff",
// disabled color
disabled: "#777",
};
export const AccentColor = {
blackgray: "#333533FF",
blackgray: "#aaa",
darkblue: "#002E59",
blue: "#00447D",
softblue: "#007CBA",
skyblue: "#00BFFF",
yellow: "#F8A824",
white: "#FEFFFE",
// disable color
disabledBorder: "#aaa",
};
export const AdminColor = {

View File

@@ -31,8 +31,8 @@ export default function LoginView() {
console.log("login user id :", id);
// router.navigate("/verification");
router.navigate(`/(application)/(user)/profile/${id}`);
// router.navigate("/(application)/home");
// router.navigate(`/(application)/(user)/profile/${id}`);
router.navigate("/(application)/(user)/home");
// router.navigate(`/(application)/profile/${id}/edit`);
}

View File

@@ -0,0 +1,33 @@
import { IMenuDrawerItem } from "@/components/_Interface/types";
export const drawerItemsPortofolio = ({
id,
}: {
id: string;
}): IMenuDrawerItem[] => [
{
icon: "create",
label: "Edit portofolio",
path: `/(application)/portofolio/${id}/edit`,
},
{
icon: "camera",
label: "Edit logo ",
path: `/(application)/portofolio/${id}/edit-logo`,
},
{
icon: "image",
label: "Edit social media ",
path: `/(application)/portofolio/${id}/edit-social-media`,
},
{
icon: "add-circle",
label: "Edit Map",
path: `/(application)/maps/${id}/edit`,
},
{
icon: "create-outline",
label: "Custom Pin Map",
path: `/(application)/maps/${id}/custom-pin`,
},
];

View File

@@ -0,0 +1,28 @@
import { IMenuDrawerItem } from "@/components/_Interface/types";
import MenuDrawerDynamicGrid from "@/components/Drawer/MenuDrawerDynamicGird";
import { router } from "expo-router";
export default function Portofolio_MenuDrawerSection({
drawerItems,
setIsDrawerOpen,
}: {
drawerItems: IMenuDrawerItem[];
setIsDrawerOpen: (value: boolean) => void;
}) {
const handlePress = (item: IMenuDrawerItem) => {
console.log("PATH >> ", item.path);
router.push(item.path as any);
setIsDrawerOpen(false);
};
return (
<>
{/* Menu Items */}
<MenuDrawerDynamicGrid
data={drawerItems}
columns={4} // Ubah ke 2 jika ingin 2 kolom per baris
onPressItem={handlePress}
/>
</>
);
}

View File

@@ -0,0 +1,35 @@
import { IMenuDrawerItem } from "@/components/_Interface/types";
export const drawerItemsProfile = ({ id }: { id: string }): IMenuDrawerItem[] => [
{
icon: "create",
label: "Edit profile",
path: `/(application)/profile/${id}/edit`,
},
{
icon: "camera",
label: "Ubah foto profile",
path: `/(application)/profile/${id}/update-photo`,
},
{
icon: "image",
label: "Ubah latar belakang",
path: `/(application)/profile/${id}/update-background`,
},
{
icon: "add-circle",
label: "Tambah portofolio",
path: `/(application)/portofolio/${id}/create`,
},
// {
// icon: "settings",
// label: "Dashboard Admin",
// path: `/(application)/profile/dashboard-admin`,
// },
{ icon: "log-out", label: "Keluar", color: "red", path: "" },
{
icon: "create-outline",
label: "Create profile",
path: `/(application)/profile/${id}/create`,
},
];

View File

@@ -115,9 +115,15 @@ export default function ProfilSection() {
</BaseBox>
))}
</View>
<TextCustom
bold
align="right"
onPress={() => router.push(`/portofolio/${id}/list`)}
>
Lihat semua
</TextCustom>
</BaseBox>
</>
);
}

View File

@@ -1,10 +1,15 @@
import { TEXT_SIZE_MEDIUM } from "@/constants/constans-value";
import {
TEXT_SIZE_LARGE,
TEXT_SIZE_MEDIUM,
TEXT_SIZE_SMALL,
} from "@/constants/constans-value";
import { Dimensions, StyleSheet } from "react-native";
import { AccentColor, MainColor } from "../constants/color-palet";
const { width } = Dimensions.get("window");
export const GStyles = StyleSheet.create({
// =============== Main Styles =============== //
container: {
flex: 1,
paddingInline: 20,
@@ -20,8 +25,25 @@ export const GStyles = StyleSheet.create({
height: "100%",
width: "100%",
},
// Style saat disabled
disabledBox: {
backgroundColor: MainColor.disabled,
borderColor: AccentColor.disabledBorder,
},
// AUTHENTICATION
inputDisabled: {
backgroundColor: "#f0f0f0",
borderColor: "#ddd",
},
inputTextDisabled: {
color: "#777",
},
inputPlaceholderDisabled: {
color: "#444",
},
// =============== Main Styles =============== //
// =============== AUTHENTICATION =============== //
authContainer: {
flex: 1,
justifyContent: "center",
@@ -40,30 +62,35 @@ export const GStyles = StyleSheet.create({
color: MainColor.yellow,
fontWeight: "bold",
},
// =============== AUTHENTICATION =============== //
// TEXT & LABEL
// =============== TEXT & LABEL =============== //
textLabel: {
fontSize: TEXT_SIZE_MEDIUM,
color: MainColor.white_gray,
fontWeight: "normal",
},
// =============== TEXT & LABEL =============== //
// Stack Header Style
// =============== STACK HEADER =============== //
headerStyle: {
backgroundColor: AccentColor.darkblue,
},
headerTitleStyle: {
color: MainColor.yellow,
fontWeight: "bold",
fontSize: TEXT_SIZE_LARGE,
},
// =============== STACK HEADER =============== //
// HOME
// =============== HOME =============== //
homeContainer: {
flex: 1,
paddingInline: 25,
paddingBlock: 10,
backgroundColor: MainColor.darkblue,
},
// =============== HOME =============== //
// =============== TAB =============== //
tabBar: {
@@ -141,14 +168,6 @@ export const GStyles = StyleSheet.create({
backgroundColor: MainColor.darkblue,
borderTopColor: AccentColor.blue,
borderTopWidth: 1,
// shadowColor: AccentColor.blue,
// shadowOffset: {
// width: 0,
// height: -1,
// },
// shadowOpacity: 0.9,
// shadowRadius: 5,
// elevation: 5,
},
bottomBarContainer: {
paddingHorizontal: 15,
@@ -157,8 +176,113 @@ export const GStyles = StyleSheet.create({
// =============== BOTTOM BAR =============== //
// =============== BUTTON =============== //
buttonCentered50Percent: {
width: "50%",
alignSelf: "center",
},
// =============== BUTTON =============== //
// =============== TEXT INPUT , TEXT AREA , SELECT =============== //
// Container utama input (View luar)
inputContainerArea: {
marginBottom: 16,
},
// Label di atas input
inputLabel: {
fontSize: TEXT_SIZE_MEDIUM,
marginBottom: 4,
fontWeight: "500",
color: MainColor.white_gray,
},
// Tanda bintang merah untuk required
inputRequired: {
color: "red",
},
// Pesan error di bawah input
inputErrorMessage: {
marginTop: 4,
fontSize: TEXT_SIZE_SMALL,
color: MainColor.red,
},
// Input Length
inputMaxLength: {
fontSize: TEXT_SIZE_SMALL,
color: MainColor.white_gray,
},
// Wrapper input (View pembungkus TextInput)
inputContainerInput: {
borderWidth: 1,
borderColor: MainColor.white_gray,
backgroundColor: MainColor.white,
flexDirection: "row",
alignItems: "center",
paddingHorizontal: 10,
height: 50,
},
// Input utama (TextInput)
inputText: {
flex: 1,
fontSize: TEXT_SIZE_MEDIUM,
paddingVertical: 0,
},
// Ikon di kiri/kanan
inputIcon: {
marginHorizontal: 4,
justifyContent: "center",
},
// Teks ikon jika berupa string
inputIconText: {
fontSize: TEXT_SIZE_LARGE,
color: "#000",
},
// Border merah jika ada error
inputErrorBorder: {
borderColor: "red",
borderWidth: 1,
},
// Placeholder input
inputPlaceholder: {
fontSize: TEXT_SIZE_MEDIUM,
color: MainColor.placeholder,
},
// TextArea untuk tambahan
textAreaInput: {
textAlignVertical: "top",
padding: 5,
height: undefined, // biar multiline bebas tinggi
},
// Select
selectModalOverlay: {
flex: 1,
backgroundColor: "rgba(0,0,0,0.3)",
justifyContent: "center",
alignItems: "center",
},
selectModalContent: {
width: "80%",
maxHeight: 300,
backgroundColor: "white",
borderRadius: 8,
overflow: "hidden",
},
selectOption: {
padding: 16,
borderBottomWidth: 1,
borderBottomColor: MainColor.white_gray,
},
// =============== TEXT INPUT , TEXT AREA , SELECT =============== //
});