Compare commits
34 Commits
bagas/26-j
...
resourcing
| Author | SHA1 | Date | |
|---|---|---|---|
| 71ea0ca5f2 | |||
| ee7efaef6a | |||
| bfb029058c | |||
| b7e774a556 | |||
| 2901d19db0 | |||
| 5c4dadbe7c | |||
| 6ac122c631 | |||
| 16559b94fe | |||
| 0698e14d36 | |||
| 3d9672154c | |||
| 55b4b1fa8d | |||
| b80968999e | |||
| 6bac89c536 | |||
| b9af7e0ca7 | |||
| 8abf23fd13 | |||
| 1a16b16f47 | |||
| 0b1fd05eec | |||
| b54693caa7 | |||
| 17e6208aae | |||
| f5cf9e1549 | |||
| 7b58e3315f | |||
| 101c9053d8 | |||
| 4a92385d6d | |||
| 7e39133c2f | |||
| e2744f0344 | |||
| 9667065bb3 | |||
| 23ae416f42 | |||
| 8fb37db0db | |||
| 258e20751e | |||
| 564ea68d29 | |||
| 4701fce07c | |||
| d58304a146 | |||
| 5577ef5d1e | |||
| c1bee77629 |
13
app.json
13
app.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"expo": {
|
"expo": {
|
||||||
"name": "hipmi-mobile",
|
"name": "HIPMI BADUNG",
|
||||||
"slug": "hipmi-mobile",
|
"slug": "hipmi-mobile",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"orientation": "portrait",
|
"orientation": "portrait",
|
||||||
@@ -38,7 +38,16 @@
|
|||||||
"resizeMode": "contain",
|
"resizeMode": "contain",
|
||||||
"backgroundColor": "#ffffff"
|
"backgroundColor": "#ffffff"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
[
|
||||||
|
"expo-camera",
|
||||||
|
{
|
||||||
|
"cameraPermission": "Allow $(PRODUCT_NAME) to access your camera",
|
||||||
|
"microphonePermission": "Allow $(PRODUCT_NAME) to access your microphone",
|
||||||
|
"recordAudioAndroid": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expo-font"
|
||||||
],
|
],
|
||||||
"experiments": {
|
"experiments": {
|
||||||
"typedRoutes": true
|
"typedRoutes": true
|
||||||
|
|||||||
138
app/(application)/(user)/_layout.tsx
Normal file
138
app/(application)/(user)/_layout.tsx
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
import { BackButton } from "@/components";
|
||||||
|
import LeftButtonCustom from "@/components/Button/BackButton";
|
||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { HeaderStyles } from "@/styles/header-styles";
|
||||||
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
|
import { router, Stack } from "expo-router";
|
||||||
|
|
||||||
|
export default function UserLayout() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Stack screenOptions={HeaderStyles}>
|
||||||
|
<Stack.Screen
|
||||||
|
name="home"
|
||||||
|
options={{
|
||||||
|
title: "HIPMI",
|
||||||
|
headerLeft: () => (
|
||||||
|
<Ionicons
|
||||||
|
name="search"
|
||||||
|
size={20}
|
||||||
|
color={MainColor.yellow}
|
||||||
|
onPress={() => router.push("/user-search")}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
headerRight: () => (
|
||||||
|
<Ionicons
|
||||||
|
name="notifications"
|
||||||
|
size={20}
|
||||||
|
color={MainColor.yellow}
|
||||||
|
onPress={() => router.push("/notifications")}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* ========== Profile Section ========= */}
|
||||||
|
<Stack.Screen
|
||||||
|
name="profile"
|
||||||
|
options={{
|
||||||
|
headerShown: false,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* ========== Portofolio Section ========= */}
|
||||||
|
<Stack.Screen
|
||||||
|
name="portofolio"
|
||||||
|
options={{
|
||||||
|
headerShown: false,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* ========== User Search Section ========= */}
|
||||||
|
<Stack.Screen
|
||||||
|
name="user-search/index"
|
||||||
|
options={{
|
||||||
|
title: "Pencarian Pengguna",
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* ========== Notification Section ========= */}
|
||||||
|
<Stack.Screen
|
||||||
|
name="notifications/index"
|
||||||
|
options={{
|
||||||
|
title: "Notifikasi",
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* ========== Event Section ========= */}
|
||||||
|
<Stack.Screen
|
||||||
|
name="event/(tabs)"
|
||||||
|
options={{
|
||||||
|
title: "Event",
|
||||||
|
headerLeft: () => (
|
||||||
|
<LeftButtonCustom path="/(application)/(user)/home" />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Stack.Screen
|
||||||
|
name="event/detail/[id]"
|
||||||
|
options={{
|
||||||
|
title: "Event Detail",
|
||||||
|
headerLeft: () => <LeftButtonCustom />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* ========== Forum Section ========= */}
|
||||||
|
<Stack.Screen
|
||||||
|
name="forum/index"
|
||||||
|
options={{
|
||||||
|
title: "Forum",
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* ========== Maps Section ========= */}
|
||||||
|
<Stack.Screen
|
||||||
|
name="maps/index"
|
||||||
|
options={{
|
||||||
|
title: "Maps",
|
||||||
|
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 Section ========= */}
|
||||||
|
<Stack.Screen
|
||||||
|
name="marketplace/index"
|
||||||
|
options={{
|
||||||
|
title: "Market Place",
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
64
app/(application)/(user)/event/(tabs)/_layout.tsx
Normal file
64
app/(application)/(user)/event/(tabs)/_layout.tsx
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { FontAwesome5, Ionicons } from "@expo/vector-icons";
|
||||||
|
import { Tabs } from "expo-router";
|
||||||
|
|
||||||
|
export default function EventLayout() {
|
||||||
|
return (
|
||||||
|
<Tabs
|
||||||
|
screenOptions={{
|
||||||
|
headerShown: false,
|
||||||
|
tabBarActiveTintColor: MainColor.yellow,
|
||||||
|
tabBarInactiveTintColor: MainColor.white_gray,
|
||||||
|
tabBarStyle: {
|
||||||
|
backgroundColor: MainColor.darkblue,
|
||||||
|
},
|
||||||
|
// tabBarButton: HapticTab,
|
||||||
|
// tabBarBackground: BlurTabBarBackground,
|
||||||
|
// tabBarStyle: Platform.select({
|
||||||
|
// ios: {
|
||||||
|
// // Use a transparent background on iOS to show the blur effect
|
||||||
|
// position: "absolute",
|
||||||
|
// },
|
||||||
|
// default: {},
|
||||||
|
// }),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="index"
|
||||||
|
options={{
|
||||||
|
title: "Home",
|
||||||
|
tabBarIcon: ({ color }) => (
|
||||||
|
<Ionicons size={20} name="home" color={color} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="status"
|
||||||
|
options={{
|
||||||
|
title: "Status",
|
||||||
|
tabBarIcon: ({ color }) => (
|
||||||
|
<Ionicons size={20} name="list" color={color} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="kontribusi"
|
||||||
|
options={{
|
||||||
|
title: "Kontribusi",
|
||||||
|
tabBarIcon: ({ color }) => (
|
||||||
|
<Ionicons size={20} name="extension-puzzle" color={color} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="riwayat"
|
||||||
|
options={{
|
||||||
|
title: "Riwayat",
|
||||||
|
tabBarIcon: ({ color }) => (
|
||||||
|
<FontAwesome5 size={20} name="history" color={color} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tabs>
|
||||||
|
);
|
||||||
|
}
|
||||||
25
app/(application)/(user)/event/(tabs)/index.tsx
Normal file
25
app/(application)/(user)/event/(tabs)/index.tsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
||||||
|
import { AccentColor, MainColor } from "@/constants/color-palet";
|
||||||
|
import { GStyles } from "@/styles/global-styles";
|
||||||
|
import { router } from "expo-router";
|
||||||
|
import { Text, TouchableHighlight, View } from "react-native";
|
||||||
|
|
||||||
|
export default function Event() {
|
||||||
|
return (
|
||||||
|
<ViewWrapper>
|
||||||
|
<TouchableHighlight onPress={() => router.push("/event/detail/1")}>
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
padding: 20,
|
||||||
|
backgroundColor: MainColor.darkblue,
|
||||||
|
borderRadius: 10,
|
||||||
|
borderColor: AccentColor.blue,
|
||||||
|
borderWidth: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text style={GStyles.textLabel}>Event</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableHighlight>
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
11
app/(application)/(user)/event/(tabs)/kontribusi.tsx
Normal file
11
app/(application)/(user)/event/(tabs)/kontribusi.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
||||||
|
import { GStyles } from "@/styles/global-styles";
|
||||||
|
import { Text } from "react-native";
|
||||||
|
|
||||||
|
export default function Kontribusi() {
|
||||||
|
return (
|
||||||
|
<ViewWrapper>
|
||||||
|
<Text style={GStyles.textLabel}>Kontribusi</Text>
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
11
app/(application)/(user)/event/(tabs)/riwayat.tsx
Normal file
11
app/(application)/(user)/event/(tabs)/riwayat.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
||||||
|
import { GStyles } from "@/styles/global-styles";
|
||||||
|
import { Text } from "react-native";
|
||||||
|
|
||||||
|
export default function Riwayat() {
|
||||||
|
return (
|
||||||
|
<ViewWrapper>
|
||||||
|
<Text style={GStyles.textLabel}>Riwayat</Text>
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
11
app/(application)/(user)/event/(tabs)/status.tsx
Normal file
11
app/(application)/(user)/event/(tabs)/status.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
||||||
|
import { GStyles } from "@/styles/global-styles";
|
||||||
|
import { Text } from "react-native";
|
||||||
|
|
||||||
|
export default function Status() {
|
||||||
|
return (
|
||||||
|
<ViewWrapper>
|
||||||
|
<Text style={GStyles.textLabel}>Status</Text>
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
14
app/(application)/(user)/event/detail/[id].tsx
Normal file
14
app/(application)/(user)/event/detail/[id].tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
||||||
|
import { GStyles } from "@/styles/global-styles";
|
||||||
|
import { useLocalSearchParams } from "expo-router";
|
||||||
|
import { Text } from "react-native";
|
||||||
|
|
||||||
|
export default function DetailEvent() {
|
||||||
|
const { id } = useLocalSearchParams();
|
||||||
|
console.log("id event >", id);
|
||||||
|
return (
|
||||||
|
<ViewWrapper>
|
||||||
|
<Text style={GStyles.textLabel}>Detail Event {id}</Text>
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
11
app/(application)/(user)/forum/index.tsx
Normal file
11
app/(application)/(user)/forum/index.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { TextCustom, ViewWrapper } from "@/components";
|
||||||
|
|
||||||
|
export default function Forum() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ViewWrapper>
|
||||||
|
<TextCustom>Forum</TextCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import NewHomeView from "@/screens/Home/UiHome";
|
import UiHome from "@/screens/Home/UiHome";
|
||||||
|
|
||||||
export default function Application() {
|
export default function Application() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<NewHomeView />
|
<UiHome />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
11
app/(application)/(user)/maps/[id]/custom-pin.tsx
Normal file
11
app/(application)/(user)/maps/[id]/custom-pin.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { TextCustom, ViewWrapper } from "@/components";
|
||||||
|
|
||||||
|
export default function MapsCustomPin() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ViewWrapper>
|
||||||
|
<TextCustom>Maps Custom Pin</TextCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
11
app/(application)/(user)/maps/[id]/edit.tsx
Normal file
11
app/(application)/(user)/maps/[id]/edit.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { TextCustom, ViewWrapper } from "@/components";
|
||||||
|
|
||||||
|
export default function MapsEdit() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ViewWrapper>
|
||||||
|
<TextCustom>Maps Edit</TextCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
59
app/(application)/(user)/maps/create.tsx
Normal file
59
app/(application)/(user)/maps/create.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
9
app/(application)/(user)/maps/index.tsx
Normal file
9
app/(application)/(user)/maps/index.tsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { TextCustom, ViewWrapper } from "@/components";
|
||||||
|
|
||||||
|
export default function Maps() {
|
||||||
|
return (
|
||||||
|
<ViewWrapper>
|
||||||
|
<TextCustom>Maps</TextCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
)
|
||||||
|
}
|
||||||
9
app/(application)/(user)/marketplace/index.tsx
Normal file
9
app/(application)/(user)/marketplace/index.tsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { TextCustom, ViewWrapper } from "@/components";
|
||||||
|
|
||||||
|
export default function Marketplace() {
|
||||||
|
return (
|
||||||
|
<ViewWrapper>
|
||||||
|
<TextCustom>Marketplace</TextCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
9
app/(application)/(user)/notifications/index.tsx
Normal file
9
app/(application)/(user)/notifications/index.tsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { TextCustom, ViewWrapper } from "@/components";
|
||||||
|
|
||||||
|
export default function Notifications() {
|
||||||
|
return (
|
||||||
|
<ViewWrapper>
|
||||||
|
<TextCustom>Notifications</TextCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
191
app/(application)/(user)/portofolio/[id]/create.tsx
Normal file
191
app/(application)/(user)/portofolio/[id]/create.tsx
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
import {
|
||||||
|
BoxButtonOnFooter,
|
||||||
|
ButtonCenteredOnly,
|
||||||
|
ButtonCustom,
|
||||||
|
Grid,
|
||||||
|
InformationBox,
|
||||||
|
LandscapeFrameUploaded,
|
||||||
|
SelectCustom,
|
||||||
|
Spacing,
|
||||||
|
StackCustom,
|
||||||
|
TextAreaCustom,
|
||||||
|
TextCustom,
|
||||||
|
TextInputCustom,
|
||||||
|
ViewWrapper,
|
||||||
|
} from "@/components";
|
||||||
|
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 { 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";
|
||||||
|
|
||||||
|
export default function PortofolioCreate() {
|
||||||
|
const { id } = useLocalSearchParams();
|
||||||
|
const [selectedCountry, setSelectedCountry] = useState<null | ICountry>(null);
|
||||||
|
const [inputValue, setInputValue] = useState<string>("");
|
||||||
|
const [data, setData] = useState({
|
||||||
|
name: "",
|
||||||
|
bidang_usaha: "",
|
||||||
|
sub_bidang_usaha: "",
|
||||||
|
alamat: "",
|
||||||
|
nomor_telepon: "",
|
||||||
|
deskripsi: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleInputValue(phoneNumber: string) {
|
||||||
|
setInputValue(phoneNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSelectedCountry(country: ICountry) {
|
||||||
|
setSelectedCountry(country);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSave() {
|
||||||
|
console.log("Selanjutnya");
|
||||||
|
router.replace(`/maps/create`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const buttonSave = (
|
||||||
|
<BoxButtonOnFooter>
|
||||||
|
<ButtonCustom onPress={handleSave}>Selanjutnya</ButtonCustom>
|
||||||
|
</BoxButtonOnFooter>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ViewWrapper footerComponent={buttonSave}>
|
||||||
|
{/* <TextCustom>Portofolio Create {id}</TextCustom> */}
|
||||||
|
<StackCustom gap={"xs"}>
|
||||||
|
<InformationBox text="Lengkapi data bisnis anda." />
|
||||||
|
<TextInputCustom
|
||||||
|
required
|
||||||
|
label="Nama Bisnis"
|
||||||
|
placeholder="Masukkan nama bisnis"
|
||||||
|
|
||||||
|
/>
|
||||||
|
<SelectCustom
|
||||||
|
label="Bidang Usaha"
|
||||||
|
required
|
||||||
|
data={dummyMasterBidangBisnis.map((item) => ({
|
||||||
|
label: item.name,
|
||||||
|
value: item.id,
|
||||||
|
}))}
|
||||||
|
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={data.sub_bidang_usaha}
|
||||||
|
onChange={(value) => {
|
||||||
|
setData({ ...(data as any), sub_bidang_usaha: value });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid.Col>
|
||||||
|
<Grid.Col
|
||||||
|
span={2}
|
||||||
|
style={{ alignItems: "center", justifyContent: "center" }}
|
||||||
|
>
|
||||||
|
<TouchableOpacity onPress={() => console.log("delete")}>
|
||||||
|
<Ionicons name="trash" size={24} color={MainColor.red} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<ButtonCenteredOnly onPress={() => console.log("add")}>
|
||||||
|
Tambah Pilihan
|
||||||
|
</ButtonCenteredOnly>
|
||||||
|
<Spacing />
|
||||||
|
|
||||||
|
<View>
|
||||||
|
<View style={{ flexDirection: "row", alignItems: "center" }}>
|
||||||
|
<TextCustom semiBold style={{ color: MainColor.white_gray }}>
|
||||||
|
Nomor Telepon
|
||||||
|
</TextCustom>
|
||||||
|
<Text style={{ color: "red" }}> *</Text>
|
||||||
|
</View>
|
||||||
|
<Spacing height={5} />
|
||||||
|
<PhoneInput
|
||||||
|
value={inputValue}
|
||||||
|
onChangePhoneNumber={handleInputValue}
|
||||||
|
selectedCountry={selectedCountry}
|
||||||
|
onChangeSelectedCountry={handleSelectedCountry}
|
||||||
|
defaultCountry="ID"
|
||||||
|
placeholder="xxx-xxx-xxx"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<Spacing />
|
||||||
|
|
||||||
|
<TextInputCustom
|
||||||
|
required
|
||||||
|
label="Alamat Bisnis"
|
||||||
|
placeholder="Masukkan alamat bisnis"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextAreaCustom
|
||||||
|
label="Deskripsi Bisnis"
|
||||||
|
placeholder="Masukkan deskripsi bisnis"
|
||||||
|
value={data.deskripsi}
|
||||||
|
onChangeText={(value: any) => setData({ ...data, deskripsi: value })}
|
||||||
|
autosize
|
||||||
|
minRows={2}
|
||||||
|
maxRows={5}
|
||||||
|
required
|
||||||
|
showCount
|
||||||
|
maxLength={100}
|
||||||
|
/>
|
||||||
|
<Spacing />
|
||||||
|
|
||||||
|
{/* Logo */}
|
||||||
|
<InformationBox text="Upload logo bisnis anda untuk di tampilaka pada portofolio." />
|
||||||
|
<LandscapeFrameUploaded />
|
||||||
|
<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"
|
||||||
|
placeholder="Masukkan username tiktok"
|
||||||
|
/>
|
||||||
|
<TextInputCustom
|
||||||
|
label="Facebook"
|
||||||
|
placeholder="Masukkan username facebook"
|
||||||
|
/>
|
||||||
|
<TextInputCustom
|
||||||
|
label="Instagram"
|
||||||
|
placeholder="Masukkan username instagram"
|
||||||
|
/>
|
||||||
|
<TextInputCustom
|
||||||
|
label="Twitter"
|
||||||
|
placeholder="Masukkan username twitter"
|
||||||
|
/>
|
||||||
|
<TextInputCustom
|
||||||
|
label="Youtube"
|
||||||
|
placeholder="Masukkan username youtube"
|
||||||
|
/>
|
||||||
|
<Spacing />
|
||||||
|
</StackCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
11
app/(application)/(user)/portofolio/[id]/edit-logo.tsx
Normal file
11
app/(application)/(user)/portofolio/[id]/edit-logo.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { TextCustom, ViewWrapper } from "@/components";
|
||||||
|
|
||||||
|
export default function PortofolioEditLogo() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ViewWrapper>
|
||||||
|
<TextCustom>Portofolio Edit Logo</TextCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { TextCustom, ViewWrapper } from "@/components";
|
||||||
|
|
||||||
|
export default function PortofolioEditSocialMedia() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ViewWrapper>
|
||||||
|
<TextCustom>Portofolio Edit Social Media</TextCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
11
app/(application)/(user)/portofolio/[id]/edit.tsx
Normal file
11
app/(application)/(user)/portofolio/[id]/edit.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { TextCustom, ViewWrapper } from "@/components";
|
||||||
|
|
||||||
|
export default function PortofolioEdit() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ViewWrapper>
|
||||||
|
<TextCustom>Portofolio Edit</TextCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
63
app/(application)/(user)/portofolio/[id]/index.tsx
Normal file
63
app/(application)/(user)/portofolio/[id]/index.tsx
Normal file
@@ -0,0 +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 { useState } from "react";
|
||||||
|
import {
|
||||||
|
Text,
|
||||||
|
TouchableOpacity
|
||||||
|
} from "react-native";
|
||||||
|
|
||||||
|
export default function Portofolio() {
|
||||||
|
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>
|
||||||
|
|
||||||
|
{/* Drawer Komponen Eksternal */}
|
||||||
|
<DrawerCustom
|
||||||
|
isVisible={isDrawerOpen}
|
||||||
|
closeDrawer={closeDrawer}
|
||||||
|
height={350}
|
||||||
|
>
|
||||||
|
<Portofolio_MenuDrawerSection
|
||||||
|
drawerItems={drawerItemsPortofolio({ id: id as string })}
|
||||||
|
setIsDrawerOpen={setIsDrawerOpen}
|
||||||
|
/>
|
||||||
|
</DrawerCustom>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
47
app/(application)/(user)/portofolio/[id]/list.tsx
Normal file
47
app/(application)/(user)/portofolio/[id]/list.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
32
app/(application)/(user)/portofolio/_layout.tsx
Normal file
32
app/(application)/(user)/portofolio/_layout.tsx
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import LeftButtonCustom from "@/components/Button/BackButton";
|
||||||
|
import { HeaderStyles } from "@/styles/header-styles";
|
||||||
|
import { Stack } from "expo-router";
|
||||||
|
|
||||||
|
export default function PortofolioLayout() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Stack
|
||||||
|
screenOptions={{
|
||||||
|
...HeaderStyles,
|
||||||
|
headerLeft: () => <LeftButtonCustom />,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* <Stack.Screen name="[id]/index" options={{ title: "Portofolio" }} /> */}
|
||||||
|
<Stack.Screen
|
||||||
|
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>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
117
app/(application)/(user)/profile/[id]/create.tsx
Normal file
117
app/(application)/(user)/profile/[id]/create.tsx
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
import {
|
||||||
|
AvatarCustom,
|
||||||
|
ButtonCenteredOnly,
|
||||||
|
ButtonCustom,
|
||||||
|
SelectCustom,
|
||||||
|
Spacing,
|
||||||
|
StackCustom,
|
||||||
|
TextInputCustom,
|
||||||
|
ViewWrapper,
|
||||||
|
} from "@/components";
|
||||||
|
import BoxButtonOnFooter from "@/components/Box/BoxButtonOnFooter";
|
||||||
|
import InformationBox from "@/components/Box/InformationBox";
|
||||||
|
import LandscapeFrameUploaded from "@/components/Image/LandscapeFrameUploaded";
|
||||||
|
import { router, useLocalSearchParams } from "expo-router";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { View } from "react-native";
|
||||||
|
|
||||||
|
export default function CreateProfile() {
|
||||||
|
const { id } = useLocalSearchParams();
|
||||||
|
const [data, setData] = useState({
|
||||||
|
name: "",
|
||||||
|
email: "",
|
||||||
|
address: "",
|
||||||
|
gender: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
const handlerSave = () => {
|
||||||
|
console.log("data create profile >>", data);
|
||||||
|
router.back();
|
||||||
|
};
|
||||||
|
|
||||||
|
const footerComponent = (
|
||||||
|
<BoxButtonOnFooter>
|
||||||
|
<ButtonCustom
|
||||||
|
onPress={handlerSave}
|
||||||
|
// disabled={!data.name || !data.email || !data.address || !data.gender}
|
||||||
|
>
|
||||||
|
Simpan
|
||||||
|
</ButtonCustom>
|
||||||
|
</BoxButtonOnFooter>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ViewWrapper footerComponent={footerComponent}>
|
||||||
|
<StackCustom>
|
||||||
|
<InformationBox text="Upload foto profile anda." />
|
||||||
|
<View style={{ alignItems: "center" }}>
|
||||||
|
<AvatarCustom size="xl" />
|
||||||
|
<Spacing />
|
||||||
|
<ButtonCenteredOnly
|
||||||
|
icon="upload"
|
||||||
|
onPress={() => router.navigate(`/take-picture/${id}`)}
|
||||||
|
>
|
||||||
|
Upload
|
||||||
|
</ButtonCenteredOnly>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Spacing />
|
||||||
|
|
||||||
|
<View>
|
||||||
|
<InformationBox text="Upload foto latar belakang anda." />
|
||||||
|
<LandscapeFrameUploaded />
|
||||||
|
<Spacing />
|
||||||
|
<ButtonCenteredOnly
|
||||||
|
icon="upload"
|
||||||
|
onPress={() => router.navigate(`/take-picture/${id}`)}
|
||||||
|
>
|
||||||
|
Upload
|
||||||
|
</ButtonCenteredOnly>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Spacing />
|
||||||
|
<TextInputCustom
|
||||||
|
required
|
||||||
|
label="Nama"
|
||||||
|
placeholder="Masukkan nama"
|
||||||
|
value={data.name}
|
||||||
|
onChangeText={(text) => setData({ ...data, name: text })}
|
||||||
|
/>
|
||||||
|
<TextInputCustom
|
||||||
|
keyboardType="email-address"
|
||||||
|
required
|
||||||
|
label="Email"
|
||||||
|
placeholder="Masukkan email"
|
||||||
|
value={data.email}
|
||||||
|
onChangeText={(text) => setData({ ...data, email: text })}
|
||||||
|
/>
|
||||||
|
<TextInputCustom
|
||||||
|
required
|
||||||
|
label="Alamat"
|
||||||
|
placeholder="Masukkan alamat"
|
||||||
|
value={data.address}
|
||||||
|
onChangeText={(text) => setData({ ...data, address: text })}
|
||||||
|
/>
|
||||||
|
<SelectCustom
|
||||||
|
label="Jenis Kelamin"
|
||||||
|
placeholder="Pilih jenis kelamin"
|
||||||
|
data={[
|
||||||
|
{ label: "Laki-laki", value: "laki-laki" },
|
||||||
|
{ label: "Perempuan", value: "perempuan" },
|
||||||
|
]}
|
||||||
|
value={data.gender}
|
||||||
|
required
|
||||||
|
onChange={(value) => setData({ ...(data as any), gender: value })}
|
||||||
|
/>
|
||||||
|
<TextInputCustom
|
||||||
|
required
|
||||||
|
label="Alamat"
|
||||||
|
placeholder="Masukkan alamat"
|
||||||
|
value={data.address}
|
||||||
|
onChangeText={(text) => setData({ ...data, address: text })}
|
||||||
|
/>
|
||||||
|
{/* <Spacing /> */}
|
||||||
|
</StackCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
115
app/(application)/(user)/profile/[id]/edit.tsx
Normal file
115
app/(application)/(user)/profile/[id]/edit.tsx
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
|
import {
|
||||||
|
ButtonCustom,
|
||||||
|
SelectCustom,
|
||||||
|
StackCustom,
|
||||||
|
TextInputCustom,
|
||||||
|
ViewWrapper,
|
||||||
|
} from "@/components";
|
||||||
|
import BoxButtonOnFooter from "@/components/Box/BoxButtonOnFooter";
|
||||||
|
import { router, useLocalSearchParams } from "expo-router";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { StyleSheet } from "react-native";
|
||||||
|
|
||||||
|
export default function ProfileEdit() {
|
||||||
|
const { id } = useLocalSearchParams();
|
||||||
|
|
||||||
|
const [data, setData] = useState({
|
||||||
|
nama: "Bagas Banuna",
|
||||||
|
email: "bagasbanuna@gmail.com",
|
||||||
|
alamat: "Jember",
|
||||||
|
selectedValue: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
const options = [
|
||||||
|
{ label: "React", value: "react" },
|
||||||
|
{ label: "Vue", value: "vue" },
|
||||||
|
{ label: "Angular", value: "angular" },
|
||||||
|
{ label: "Svelte", value: "svelte" },
|
||||||
|
{ label: "Next.js", value: "nextjs" },
|
||||||
|
{ label: "Nuxt.js", value: "nuxtjs" },
|
||||||
|
{ label: "Remix", value: "remix" },
|
||||||
|
{ label: "Sapper", value: "sapper" },
|
||||||
|
{ label: "SvelteKit", value: "sveltekit" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const handleSave = () => {
|
||||||
|
console.log({
|
||||||
|
nama: data.nama,
|
||||||
|
email: data.email,
|
||||||
|
alamat: data.alamat,
|
||||||
|
selectedValue: data.selectedValue,
|
||||||
|
});
|
||||||
|
router.back();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ViewWrapper
|
||||||
|
footerComponent={
|
||||||
|
<BoxButtonOnFooter>
|
||||||
|
<ButtonCustom
|
||||||
|
// disabled={
|
||||||
|
// !data.nama || !data.email || !data.alamat || !data.selectedValue
|
||||||
|
// }
|
||||||
|
onPress={handleSave}
|
||||||
|
>
|
||||||
|
Simpan
|
||||||
|
</ButtonCustom>
|
||||||
|
</BoxButtonOnFooter>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<StackCustom gap={"xs"}>
|
||||||
|
<SelectCustom
|
||||||
|
label="Framework"
|
||||||
|
placeholder="Pilih framework favoritmu"
|
||||||
|
data={options}
|
||||||
|
value={data.selectedValue}
|
||||||
|
onChange={(value) => {
|
||||||
|
setData({ ...(data as any), selectedValue: value });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextInputCustom
|
||||||
|
label="Nama"
|
||||||
|
placeholder="Nama"
|
||||||
|
value={data.nama}
|
||||||
|
onChangeText={(text) => {
|
||||||
|
setData({ ...data, nama: text });
|
||||||
|
}}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<TextInputCustom
|
||||||
|
label="Email"
|
||||||
|
placeholder="Email"
|
||||||
|
value={data.email}
|
||||||
|
onChangeText={(text) => {
|
||||||
|
setData({ ...data, email: text });
|
||||||
|
}}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<TextInputCustom
|
||||||
|
label="Alamat"
|
||||||
|
placeholder="Alamat"
|
||||||
|
value={data.alamat}
|
||||||
|
onChangeText={(text) => {
|
||||||
|
setData({ ...data, alamat: text });
|
||||||
|
}}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</StackCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: "center",
|
||||||
|
padding: 20,
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
marginTop: 20,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: "bold",
|
||||||
|
},
|
||||||
|
});
|
||||||
83
app/(application)/(user)/profile/[id]/index.tsx
Normal file
83
app/(application)/(user)/profile/[id]/index.tsx
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
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 { 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, { 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 openDrawer = () => {
|
||||||
|
setIsDrawerOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeDrawer = () => {
|
||||||
|
setIsDrawerOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLogout = () => {
|
||||||
|
console.log("User logout");
|
||||||
|
router.replace("/");
|
||||||
|
setShowLogoutAlert(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ViewWrapper>
|
||||||
|
{/* Header */}
|
||||||
|
<Stack.Screen
|
||||||
|
options={{
|
||||||
|
title: "Profile",
|
||||||
|
headerLeft: () => <LeftButtonCustom />,
|
||||||
|
headerRight: () => (
|
||||||
|
<TouchableOpacity onPress={openDrawer}>
|
||||||
|
<Ionicons
|
||||||
|
name="ellipsis-vertical"
|
||||||
|
size={20}
|
||||||
|
color={MainColor.yellow}
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
),
|
||||||
|
headerStyle: GStyles.headerStyle,
|
||||||
|
headerTitleStyle: GStyles.headerTitleStyle,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<ProfilSection />
|
||||||
|
</ViewWrapper>
|
||||||
|
|
||||||
|
{/* Drawer Komponen Eksternal */}
|
||||||
|
<DrawerCustom
|
||||||
|
height={350}
|
||||||
|
isVisible={isDrawerOpen}
|
||||||
|
closeDrawer={closeDrawer}
|
||||||
|
>
|
||||||
|
<Profile_MenuDrawerSection
|
||||||
|
drawerItems={drawerItemsProfile({ id: id as string })}
|
||||||
|
setShowLogoutAlert={setShowLogoutAlert}
|
||||||
|
setIsDrawerOpen={setIsDrawerOpen}
|
||||||
|
/>
|
||||||
|
</DrawerCustom>
|
||||||
|
|
||||||
|
{/* Alert Komponen Eksternal */}
|
||||||
|
<AlertCustom
|
||||||
|
isVisible={showLogoutAlert}
|
||||||
|
onLeftPress={() => setShowLogoutAlert(false)}
|
||||||
|
onRightPress={handleLogout}
|
||||||
|
title="Apakah anda yakin ingin keluar?"
|
||||||
|
textLeft="Batal"
|
||||||
|
textRight="Keluar"
|
||||||
|
colorRight={MainColor.red}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
190
app/(application)/(user)/profile/[id]/take-picture2.txt
Normal file
190
app/(application)/(user)/profile/[id]/take-picture2.txt
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
// COMPONENT : Jika ingin uoload gambar dan video gunakan component ini
|
||||||
|
|
||||||
|
import {
|
||||||
|
ButtonCustom,
|
||||||
|
Spacing,
|
||||||
|
StackCustom,
|
||||||
|
ViewWrapper
|
||||||
|
} from "@/components";
|
||||||
|
import AntDesign from "@expo/vector-icons/AntDesign";
|
||||||
|
import Feather from "@expo/vector-icons/Feather";
|
||||||
|
import FontAwesome6 from "@expo/vector-icons/FontAwesome6";
|
||||||
|
import {
|
||||||
|
CameraMode,
|
||||||
|
CameraType,
|
||||||
|
CameraView,
|
||||||
|
useCameraPermissions,
|
||||||
|
} from "expo-camera";
|
||||||
|
import { Image } from "expo-image";
|
||||||
|
import { router } from "expo-router";
|
||||||
|
import { useRef, useState } from "react";
|
||||||
|
import { Button, Pressable, StyleSheet, Text, View } from "react-native";
|
||||||
|
|
||||||
|
export default function TakePictureProfile2() {
|
||||||
|
const [permission, requestPermission] = useCameraPermissions();
|
||||||
|
const ref = useRef<CameraView>(null);
|
||||||
|
const [uri, setUri] = useState<string | null>(null);
|
||||||
|
const [mode, setMode] = useState<CameraMode>("picture");
|
||||||
|
const [facing, setFacing] = useState<CameraType>("back");
|
||||||
|
const [recording, setRecording] = useState(false);
|
||||||
|
|
||||||
|
if (!permission?.granted) {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Text style={{ textAlign: "center" }}>
|
||||||
|
We need your permission to use the camera
|
||||||
|
</Text>
|
||||||
|
<Button onPress={requestPermission} title="Grant permission" />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const takePicture = async () => {
|
||||||
|
const photo = await ref.current?.takePictureAsync();
|
||||||
|
setUri(photo?.uri || null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const recordVideo = async () => {
|
||||||
|
if (recording) {
|
||||||
|
setRecording(false);
|
||||||
|
ref.current?.stopRecording();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setRecording(true);
|
||||||
|
const video = await ref.current?.recordAsync();
|
||||||
|
console.log({ video });
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleMode = () => {
|
||||||
|
setMode((prev) => (prev === "picture" ? "video" : "picture"));
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleFacing = () => {
|
||||||
|
setFacing((prev) => (prev === "back" ? "front" : "back"));
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderPicture = () => {
|
||||||
|
console.log("renderPicture", uri);
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Image
|
||||||
|
source={uri ? uri : null}
|
||||||
|
contentFit="contain"
|
||||||
|
style={{ width: 340, aspectRatio: 1 }}
|
||||||
|
/>
|
||||||
|
<Spacing />
|
||||||
|
|
||||||
|
<StackCustom>
|
||||||
|
<ButtonCustom onPress={() => setUri(null)} title="Foto ulang" />
|
||||||
|
<ButtonCustom
|
||||||
|
onPress={() => {
|
||||||
|
console.log("Update foto");
|
||||||
|
router.back();
|
||||||
|
}}
|
||||||
|
title="Update Foto"
|
||||||
|
/>
|
||||||
|
</StackCustom>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderCameraUI = () => {
|
||||||
|
return (
|
||||||
|
<View style={styles.cameraOverlay}>
|
||||||
|
<View style={styles.shutterContainer}>
|
||||||
|
<Pressable onPress={toggleMode}>
|
||||||
|
{mode === "picture" ? (
|
||||||
|
<AntDesign name="picture" size={32} color="white" />
|
||||||
|
) : (
|
||||||
|
<Feather name="video" size={32} color="white" />
|
||||||
|
)}
|
||||||
|
</Pressable>
|
||||||
|
|
||||||
|
<Pressable onPress={mode === "picture" ? takePicture : recordVideo}>
|
||||||
|
{({ pressed }) => (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.shutterBtn,
|
||||||
|
{
|
||||||
|
opacity: pressed ? 0.5 : 1,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.shutterBtnInner,
|
||||||
|
{
|
||||||
|
backgroundColor: mode === "picture" ? "white" : "red",
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</Pressable>
|
||||||
|
|
||||||
|
<Pressable onPress={toggleFacing}>
|
||||||
|
<FontAwesome6 name="rotate-left" size={32} color="white" />
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{uri ? (
|
||||||
|
<ViewWrapper>
|
||||||
|
<View style={styles.container}>{renderPicture()}</View>
|
||||||
|
</ViewWrapper>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<CameraView
|
||||||
|
style={styles.camera}
|
||||||
|
ref={ref}
|
||||||
|
mode={mode}
|
||||||
|
facing={facing}
|
||||||
|
mute={false}
|
||||||
|
responsiveOrientationWhenOrientationLocked
|
||||||
|
/>
|
||||||
|
{renderCameraUI()}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
camera: {
|
||||||
|
flex: 1,
|
||||||
|
width: "100%",
|
||||||
|
},
|
||||||
|
cameraOverlay: {
|
||||||
|
...StyleSheet.absoluteFillObject,
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
padding: 44,
|
||||||
|
},
|
||||||
|
shutterContainer: {
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
shutterBtn: {
|
||||||
|
backgroundColor: "transparent",
|
||||||
|
borderWidth: 5,
|
||||||
|
borderColor: "white",
|
||||||
|
width: 85,
|
||||||
|
height: 85,
|
||||||
|
borderRadius: 45,
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
},
|
||||||
|
shutterBtnInner: {
|
||||||
|
width: 70,
|
||||||
|
height: 70,
|
||||||
|
borderRadius: 50,
|
||||||
|
},
|
||||||
|
});
|
||||||
47
app/(application)/(user)/profile/[id]/update-background.tsx
Normal file
47
app/(application)/(user)/profile/[id]/update-background.tsx
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import {
|
||||||
|
BaseBox,
|
||||||
|
BoxButtonOnFooter,
|
||||||
|
ButtonCenteredOnly,
|
||||||
|
ButtonCustom,
|
||||||
|
} from "@/components";
|
||||||
|
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
||||||
|
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 footerComponent={buttonFooter}>
|
||||||
|
<BaseBox
|
||||||
|
style={{ alignItems: "center", justifyContent: "center", height: 250 }}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
source={DUMMY_IMAGE.background}
|
||||||
|
resizeMode="cover"
|
||||||
|
style={{ width: "100%", height: "100%", borderRadius: 10 }}
|
||||||
|
/>
|
||||||
|
</BaseBox>
|
||||||
|
|
||||||
|
<ButtonCenteredOnly
|
||||||
|
icon="upload"
|
||||||
|
onPress={() => router.navigate(`/(application)/take-picture/${id}`)}
|
||||||
|
>
|
||||||
|
Update
|
||||||
|
</ButtonCenteredOnly>
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
52
app/(application)/(user)/profile/[id]/update-photo.tsx
Normal file
52
app/(application)/(user)/profile/[id]/update-photo.tsx
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import {
|
||||||
|
BaseBox,
|
||||||
|
BoxButtonOnFooter,
|
||||||
|
ButtonCenteredOnly,
|
||||||
|
ButtonCustom,
|
||||||
|
} from "@/components";
|
||||||
|
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
||||||
|
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 footerComponent={buttonFooter}>
|
||||||
|
<BaseBox
|
||||||
|
style={{ alignItems: "center", justifyContent: "center", height: 250 }}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
source={DUMMY_IMAGE.avatar}
|
||||||
|
resizeMode="cover"
|
||||||
|
style={{ width: 200, height: 200 }}
|
||||||
|
/>
|
||||||
|
</BaseBox>
|
||||||
|
|
||||||
|
<ButtonCenteredOnly
|
||||||
|
icon="upload"
|
||||||
|
onPress={() => {
|
||||||
|
console.log("Update photo >>", id);
|
||||||
|
router.navigate(`/(application)/take-picture/${id}`);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Update
|
||||||
|
</ButtonCenteredOnly>
|
||||||
|
|
||||||
|
{/* <Spacing />
|
||||||
|
<ButtonCustom>Test</ButtonCustom> */}
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
34
app/(application)/(user)/profile/_layout.tsx
Normal file
34
app/(application)/(user)/profile/_layout.tsx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { BackButton } from "@/components";
|
||||||
|
import { GStyles } from "@/styles/global-styles";
|
||||||
|
import { Stack } from "expo-router";
|
||||||
|
|
||||||
|
export default function ProfileLayout() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Stack
|
||||||
|
screenOptions={{
|
||||||
|
headerStyle: GStyles.headerStyle,
|
||||||
|
headerTitleStyle: GStyles.headerTitleStyle,
|
||||||
|
headerTitleAlign: "center",
|
||||||
|
headerBackButtonDisplayMode: "minimal",
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* <Stack.Screen name="[id]/index" options={{ headerShown: false }} /> */}
|
||||||
|
<Stack.Screen name="[id]/edit" options={{ title: "Edit Profile" }} />
|
||||||
|
<Stack.Screen
|
||||||
|
name="[id]/update-photo"
|
||||||
|
options={{ title: "Update Foto" }}
|
||||||
|
/>
|
||||||
|
<Stack.Screen
|
||||||
|
name="[id]/update-background"
|
||||||
|
options={{ title: "Update Latar Belakang" }}
|
||||||
|
/>
|
||||||
|
<Stack.Screen
|
||||||
|
name="[id]/create"
|
||||||
|
options={{ title: "Buat Profile" }}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
9
app/(application)/(user)/user-search/index.tsx
Normal file
9
app/(application)/(user)/user-search/index.tsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { TextCustom, ViewWrapper } from "@/components";
|
||||||
|
|
||||||
|
export default function UserSearch() {
|
||||||
|
return (
|
||||||
|
<ViewWrapper>
|
||||||
|
<TextCustom>User Search</TextCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,96 +1,19 @@
|
|||||||
import { AccentColor, MainColor } from "@/constants/color-palet";
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { HeaderStyles } from "@/styles/header-styles";
|
||||||
import { Ionicons } from "@expo/vector-icons";
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
import { router, Stack } from "expo-router";
|
import { router, Stack } from "expo-router";
|
||||||
|
|
||||||
export default function ApplicationLayout() {
|
export default function ApplicationLayout() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Stack
|
<Stack screenOptions={HeaderStyles}>
|
||||||
screenOptions={{
|
<Stack.Screen name="(user)" options={{ headerShown: false }} />
|
||||||
headerStyle: { backgroundColor: MainColor.darkblue },
|
|
||||||
headerTitleStyle: { color: MainColor.yellow, fontWeight: "bold" },
|
|
||||||
headerTitleAlign: "center",
|
|
||||||
contentStyle: {
|
|
||||||
borderBottomColor: AccentColor.blue,
|
|
||||||
borderBottomWidth: 2,
|
|
||||||
},
|
|
||||||
headerLargeStyle: {
|
|
||||||
backgroundColor: MainColor.darkblue,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Stack.Screen
|
|
||||||
name="home"
|
|
||||||
options={{
|
|
||||||
title: "HIPMI",
|
|
||||||
headerLeft: () => (
|
|
||||||
<Ionicons
|
|
||||||
name="search"
|
|
||||||
size={20}
|
|
||||||
color={MainColor.yellow}
|
|
||||||
onPress={() => router.back()}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
headerRight: () => (
|
|
||||||
<Ionicons
|
|
||||||
name="notifications"
|
|
||||||
size={20}
|
|
||||||
color={MainColor.yellow}
|
|
||||||
onPress={() => router.back()}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
|
{/* Take Picture */}
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="forum/index"
|
name="take-picture/[id]/index"
|
||||||
options={{
|
options={{
|
||||||
title: "Forum",
|
title: "Ambil Gambar",
|
||||||
headerLeft: () => (
|
|
||||||
<Ionicons
|
|
||||||
name="arrow-back"
|
|
||||||
size={20}
|
|
||||||
color={MainColor.yellow}
|
|
||||||
onPress={() => router.back()}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Stack.Screen
|
|
||||||
name="maps/index"
|
|
||||||
options={{
|
|
||||||
title: "Maps",
|
|
||||||
headerLeft: () => (
|
|
||||||
<Ionicons
|
|
||||||
name="arrow-back"
|
|
||||||
size={20}
|
|
||||||
color={MainColor.yellow}
|
|
||||||
onPress={() => router.back()}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Stack.Screen
|
|
||||||
name="market-place/index"
|
|
||||||
options={{
|
|
||||||
title: "Market Place",
|
|
||||||
headerLeft: () => (
|
|
||||||
<Ionicons
|
|
||||||
name="arrow-back"
|
|
||||||
size={20}
|
|
||||||
color={MainColor.yellow}
|
|
||||||
onPress={() => router.back()}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Stack.Screen
|
|
||||||
name="profile/index"
|
|
||||||
options={{
|
|
||||||
title: "Profile",
|
|
||||||
headerLeft: () => (
|
headerLeft: () => (
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name="arrow-back"
|
name="arrow-back"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {
|
import {
|
||||||
View,
|
View,
|
||||||
@@ -86,7 +85,7 @@ const CustomTabNavigator = () => {
|
|||||||
activeIcon: "notifications",
|
activeIcon: "notifications",
|
||||||
label: "Forum",
|
label: "Forum",
|
||||||
component: NotificationScreen,
|
component: NotificationScreen,
|
||||||
path: "/(application)/(home-tabs)/forum",
|
path: "/forum",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "profile",
|
id: "profile",
|
||||||
@@ -94,7 +93,7 @@ const CustomTabNavigator = () => {
|
|||||||
activeIcon: "person",
|
activeIcon: "person",
|
||||||
label: "Katalog",
|
label: "Katalog",
|
||||||
component: ProfileScreen,
|
component: ProfileScreen,
|
||||||
path: "/(application)/(home-tabs)/katalog",
|
path: "/profile",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -102,7 +101,7 @@ const CustomTabNavigator = () => {
|
|||||||
// Function untuk handle tab press
|
// Function untuk handle tab press
|
||||||
const handleTabPress = (tabId: string) => {
|
const handleTabPress = (tabId: string) => {
|
||||||
setActiveTab(tabId);
|
setActiveTab(tabId);
|
||||||
// setShowHome(false); // Hide home when any tab is pressed
|
setShowHome(false); // Hide home when any tab is pressed
|
||||||
};
|
};
|
||||||
|
|
||||||
// Determine which component to show
|
// Determine which component to show
|
||||||
@@ -110,8 +109,9 @@ const CustomTabNavigator = () => {
|
|||||||
if (showHome || activeTab === "home") {
|
if (showHome || activeTab === "home") {
|
||||||
return HomeScreen;
|
return HomeScreen;
|
||||||
}
|
}
|
||||||
const selectedTab = tabs.find((tab) => tab.id === activeTab);
|
// const selectedTab = tabs.find((tab) => tab.id === activeTab);
|
||||||
return selectedTab ? selectedTab.component : HomeScreen;
|
// return selectedTab ? selectedTab.component : HomeScreen;
|
||||||
|
return HomeScreen
|
||||||
};
|
};
|
||||||
|
|
||||||
const ActiveComponent = getActiveComponent();
|
const ActiveComponent = getActiveComponent();
|
||||||
@@ -135,7 +135,7 @@ const CustomTabNavigator = () => {
|
|||||||
label={e.label}
|
label={e.label}
|
||||||
isActive={activeTab === e.id && !showHome}
|
isActive={activeTab === e.id && !showHome}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
// handleTabPress(e.id);
|
handleTabPress(e.id);
|
||||||
router.push(e.path as any);
|
router.push(e.path as any);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
import { Text, View } from "react-native";
|
|
||||||
|
|
||||||
export default function Event() {
|
|
||||||
return (
|
|
||||||
<View>
|
|
||||||
<Text>Event</Text>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { Text, View } from "react-native";
|
|
||||||
|
|
||||||
export default function Forum() {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<View>
|
|
||||||
<Text>Forum</Text>
|
|
||||||
</View>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import { Text, View } from "react-native";
|
|
||||||
|
|
||||||
export default function Maps() {
|
|
||||||
return (
|
|
||||||
<View>
|
|
||||||
<Text>Maps</Text>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import { Text, View } from "react-native";
|
|
||||||
|
|
||||||
export default function MarketPlace() {
|
|
||||||
return (
|
|
||||||
<View>
|
|
||||||
<Text>Market Place</Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import { Text, View } from "react-native";
|
|
||||||
|
|
||||||
export default function Profile() {
|
|
||||||
return (
|
|
||||||
<View>
|
|
||||||
<Text>Profile</Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
171
app/(application)/take-picture/[id]/index.tsx
Normal file
171
app/(application)/take-picture/[id]/index.tsx
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
import {
|
||||||
|
ButtonCustom,
|
||||||
|
Spacing,
|
||||||
|
StackCustom,
|
||||||
|
ViewWrapper
|
||||||
|
} from "@/components";
|
||||||
|
import AntDesign from "@expo/vector-icons/AntDesign";
|
||||||
|
import FontAwesome6 from "@expo/vector-icons/FontAwesome6";
|
||||||
|
import { CameraType, CameraView, useCameraPermissions } from "expo-camera";
|
||||||
|
import { Image } from "expo-image";
|
||||||
|
import * as ImagePicker from "expo-image-picker";
|
||||||
|
import { router, useLocalSearchParams } from "expo-router";
|
||||||
|
import { useRef, useState } from "react";
|
||||||
|
import { Pressable, StyleSheet, Text, View } from "react-native";
|
||||||
|
|
||||||
|
export default function TakePicture() {
|
||||||
|
const { id } = useLocalSearchParams();
|
||||||
|
// console.log("Take Picture ID >>", id);
|
||||||
|
|
||||||
|
const [permission, requestPermission] = useCameraPermissions();
|
||||||
|
const ref = useRef<CameraView>(null);
|
||||||
|
const [uri, setUri] = useState<string | null>(null);
|
||||||
|
const [facing, setFacing] = useState<CameraType>("back");
|
||||||
|
|
||||||
|
if (!permission?.granted) {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Text style={{ textAlign: "center" }}>
|
||||||
|
We need your permission to use the camera
|
||||||
|
</Text>
|
||||||
|
<Pressable onPress={requestPermission}>
|
||||||
|
<Text style={{ color: "blue", marginTop: 10 }}>Grant permission</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const takePicture = async () => {
|
||||||
|
const photo = await ref.current?.takePictureAsync();
|
||||||
|
setUri(photo?.uri || null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const pickImage = async () => {
|
||||||
|
const result = await ImagePicker.launchImageLibraryAsync({
|
||||||
|
mediaTypes: ImagePicker.MediaTypeOptions.Images,
|
||||||
|
allowsEditing: true,
|
||||||
|
aspect: [1, 1],
|
||||||
|
quality: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result.canceled) {
|
||||||
|
setUri(result.assets[0].uri);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleFacing = () => {
|
||||||
|
setFacing((prev) => (prev === "back" ? "front" : "back"));
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderPicture = () => {
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Image
|
||||||
|
source={uri ? uri : null}
|
||||||
|
contentFit="contain"
|
||||||
|
style={{ width: 340, aspectRatio: 1 }}
|
||||||
|
/>
|
||||||
|
<Spacing />
|
||||||
|
|
||||||
|
<StackCustom >
|
||||||
|
<ButtonCustom onPress={() => setUri(null)} title="Foto ulang" />
|
||||||
|
<ButtonCustom
|
||||||
|
onPress={() => {
|
||||||
|
console.log("Upload picture >>", id);
|
||||||
|
router.back();
|
||||||
|
}}
|
||||||
|
title="Upload Foto"
|
||||||
|
/>
|
||||||
|
</StackCustom>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderCameraUI = () => {
|
||||||
|
return (
|
||||||
|
<View style={styles.cameraOverlay}>
|
||||||
|
<View style={styles.shutterContainer}>
|
||||||
|
<Pressable onPress={toggleFacing}>
|
||||||
|
<FontAwesome6 name="rotate-left" size={32} color="white" />
|
||||||
|
</Pressable>
|
||||||
|
|
||||||
|
<Pressable onPress={takePicture}>
|
||||||
|
{({ pressed }) => (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.shutterBtn,
|
||||||
|
{
|
||||||
|
opacity: pressed ? 0.5 : 1,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<View style={styles.shutterBtnInner} />
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</Pressable>
|
||||||
|
|
||||||
|
<Pressable onPress={pickImage}>
|
||||||
|
<AntDesign name="folderopen" size={32} color="white" />
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{uri ? (
|
||||||
|
<ViewWrapper>
|
||||||
|
<View style={styles.container}>{renderPicture()}</View>
|
||||||
|
</ViewWrapper>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<CameraView
|
||||||
|
style={styles.camera}
|
||||||
|
ref={ref}
|
||||||
|
facing={facing}
|
||||||
|
responsiveOrientationWhenOrientationLocked
|
||||||
|
/>
|
||||||
|
{renderCameraUI()}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
camera: {
|
||||||
|
flex: 1,
|
||||||
|
width: "100%",
|
||||||
|
},
|
||||||
|
cameraOverlay: {
|
||||||
|
...StyleSheet.absoluteFillObject,
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
padding: 44,
|
||||||
|
},
|
||||||
|
shutterContainer: {
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
shutterBtn: {
|
||||||
|
backgroundColor: "transparent",
|
||||||
|
borderWidth: 5,
|
||||||
|
borderColor: "white",
|
||||||
|
width: 85,
|
||||||
|
height: 85,
|
||||||
|
borderRadius: 45,
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
},
|
||||||
|
shutterBtnInner: {
|
||||||
|
width: 70,
|
||||||
|
height: 70,
|
||||||
|
borderRadius: 50,
|
||||||
|
backgroundColor: "white",
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -1,9 +1,16 @@
|
|||||||
import { Text, View } from "react-native";
|
import { StackCustom, TextCustom, ViewWrapper } from "@/components";
|
||||||
|
|
||||||
export default function NotFoundScreen() {
|
export default function NotFoundScreen() {
|
||||||
return (
|
return (
|
||||||
<View>
|
<ViewWrapper>
|
||||||
<Text>Not Found</Text>
|
<StackCustom align="center" gap={0} style={{justifyContent: "center", alignItems: "center", flex: 1}}>
|
||||||
</View>
|
<TextCustom size="large" bold style={{fontSize: 100}}>
|
||||||
)
|
404
|
||||||
|
</TextCustom>
|
||||||
|
<TextCustom size="large" bold>
|
||||||
|
Sorry, File Not Found
|
||||||
|
</TextCustom>
|
||||||
|
</StackCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
@@ -1,34 +1,32 @@
|
|||||||
import { MainColor } from "@/constants/color-palet";
|
import { MainColor } from "@/constants/color-palet";
|
||||||
import { Stack } from "expo-router";
|
import { Stack } from "expo-router";
|
||||||
|
import "react-native-gesture-handler";
|
||||||
import { SafeAreaProvider } from "react-native-safe-area-context";
|
import { SafeAreaProvider } from "react-native-safe-area-context";
|
||||||
|
|
||||||
export default function RootLayout() {
|
export default function RootLayout() {
|
||||||
return (
|
return (
|
||||||
<SafeAreaProvider
|
<>
|
||||||
style={{
|
<SafeAreaProvider>
|
||||||
backgroundColor: MainColor.darkblue,
|
<Stack
|
||||||
}}
|
screenOptions={{
|
||||||
>
|
headerStyle: { backgroundColor: MainColor.darkblue },
|
||||||
<Stack
|
headerTitleStyle: { color: MainColor.yellow, fontWeight: "bold" },
|
||||||
screenOptions={{
|
headerTitleAlign: "center",
|
||||||
headerStyle: { backgroundColor: MainColor.darkblue },
|
}}
|
||||||
headerTitleStyle: { color: MainColor.yellow, fontWeight: "bold" },
|
>
|
||||||
headerTitleAlign: "center",
|
<Stack.Screen name="index" options={{ title: "" }} />
|
||||||
// contentStyle: {
|
<Stack.Screen name="+not-found" options={{ title: "" }} />
|
||||||
// borderBottomColor: AccentColor.blue,
|
<Stack.Screen
|
||||||
// borderBottomWidth: 2,
|
name="verification"
|
||||||
// },
|
options={{ title: "", headerBackVisible: false }}
|
||||||
// headerLargeStyle: {
|
/>
|
||||||
// backgroundColor: MainColor.darkblue,
|
<Stack.Screen
|
||||||
// },
|
name="register"
|
||||||
// headerShadowVisible: false,
|
options={{ title: "", headerBackVisible: false }}
|
||||||
}}
|
/>
|
||||||
>
|
<Stack.Screen name="(application)" options={{ headerShown: false }} />
|
||||||
<Stack.Screen name="index" options={{ headerShown: false }} />
|
</Stack>
|
||||||
<Stack.Screen name="verification" options={{ headerShown: false }} />
|
</SafeAreaProvider>
|
||||||
<Stack.Screen name="register" options={{ headerShown: false }} />
|
</>
|
||||||
<Stack.Screen name="(application)" options={{ headerShown: false }} />
|
|
||||||
</Stack>
|
|
||||||
</SafeAreaProvider>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
assets/images/dummy/dummy-avatar.png
Normal file
BIN
assets/images/dummy/dummy-avatar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
BIN
assets/images/dummy/dummy-image-background.jpg
Normal file
BIN
assets/images/dummy/dummy-image-background.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
119
bun.lock
119
bun.lock
@@ -6,26 +6,29 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/vector-icons": "^14.1.0",
|
"@expo/vector-icons": "^14.1.0",
|
||||||
"@react-navigation/bottom-tabs": "^7.4.2",
|
"@react-navigation/bottom-tabs": "^7.4.2",
|
||||||
|
"@react-navigation/drawer": "^7.5.2",
|
||||||
"@react-navigation/elements": "^2.3.8",
|
"@react-navigation/elements": "^2.3.8",
|
||||||
"@react-navigation/native": "^7.1.6",
|
"@react-navigation/native": "^7.1.6",
|
||||||
"@react-navigation/native-stack": "^7.3.21",
|
"@react-navigation/native-stack": "^7.3.21",
|
||||||
"@types/react-native-vector-icons": "^6.4.18",
|
"@types/react-native-vector-icons": "^6.4.18",
|
||||||
"expo": "~53.0.12",
|
"expo": "53.0.17",
|
||||||
"expo-blur": "~14.1.5",
|
"expo-blur": "~14.1.5",
|
||||||
"expo-constants": "~17.1.6",
|
"expo-camera": "~16.1.10",
|
||||||
"expo-font": "~13.3.1",
|
"expo-constants": "~17.1.7",
|
||||||
|
"expo-font": "~13.3.2",
|
||||||
"expo-haptics": "~14.1.4",
|
"expo-haptics": "~14.1.4",
|
||||||
"expo-image": "~2.3.0",
|
"expo-image": "~2.3.2",
|
||||||
"expo-linking": "~7.1.5",
|
"expo-image-picker": "~16.1.4",
|
||||||
"expo-router": "~5.1.0",
|
"expo-linking": "~7.1.7",
|
||||||
"expo-splash-screen": "~0.30.9",
|
"expo-router": "~5.1.3",
|
||||||
|
"expo-splash-screen": "~0.30.10",
|
||||||
"expo-status-bar": "~2.2.3",
|
"expo-status-bar": "~2.2.3",
|
||||||
"expo-symbols": "~0.4.5",
|
"expo-symbols": "~0.4.5",
|
||||||
"expo-system-ui": "~5.0.9",
|
"expo-system-ui": "~5.0.10",
|
||||||
"expo-web-browser": "~14.2.0",
|
"expo-web-browser": "~14.2.0",
|
||||||
"react": "19.0.0",
|
"react": "19.0.0",
|
||||||
"react-dom": "19.0.0",
|
"react-dom": "19.0.0",
|
||||||
"react-native": "0.79.4",
|
"react-native": "0.79.5",
|
||||||
"react-native-gesture-handler": "~2.24.0",
|
"react-native-gesture-handler": "~2.24.0",
|
||||||
"react-native-international-phone-number": "^0.9.3",
|
"react-native-international-phone-number": "^0.9.3",
|
||||||
"react-native-otp-entry": "^1.8.5",
|
"react-native-otp-entry": "^1.8.5",
|
||||||
@@ -260,37 +263,37 @@
|
|||||||
|
|
||||||
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.3.2", "", { "dependencies": { "@eslint/core": "^0.15.0", "levn": "^0.4.1" } }, "sha512-4SaFZCNfJqvk/kenHpI8xvN42DMaoycy4PzKc5otHxRswww1kAt82OlBuwRVLofCACCTZEcla2Ydxv8scMXaTg=="],
|
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.3.2", "", { "dependencies": { "@eslint/core": "^0.15.0", "levn": "^0.4.1" } }, "sha512-4SaFZCNfJqvk/kenHpI8xvN42DMaoycy4PzKc5otHxRswww1kAt82OlBuwRVLofCACCTZEcla2Ydxv8scMXaTg=="],
|
||||||
|
|
||||||
"@expo/cli": ["@expo/cli@0.24.15", "", { "dependencies": { "@0no-co/graphql.web": "^1.0.8", "@babel/runtime": "^7.20.0", "@expo/code-signing-certificates": "^0.0.5", "@expo/config": "~11.0.10", "@expo/config-plugins": "~10.0.3", "@expo/devcert": "^1.1.2", "@expo/env": "~1.0.5", "@expo/image-utils": "^0.7.4", "@expo/json-file": "^9.1.4", "@expo/metro-config": "~0.20.15", "@expo/osascript": "^2.2.4", "@expo/package-manager": "^1.8.4", "@expo/plist": "^0.3.4", "@expo/prebuild-config": "^9.0.7", "@expo/spawn-async": "^1.7.2", "@expo/ws-tunnel": "^1.0.1", "@expo/xcpretty": "^4.3.0", "@react-native/dev-middleware": "0.79.4", "@urql/core": "^5.0.6", "@urql/exchange-retry": "^1.3.0", "accepts": "^1.3.8", "arg": "^5.0.2", "better-opn": "~3.0.2", "bplist-creator": "0.1.0", "bplist-parser": "^0.3.1", "chalk": "^4.0.0", "ci-info": "^3.3.0", "compression": "^1.7.4", "connect": "^3.7.0", "debug": "^4.3.4", "env-editor": "^0.4.1", "freeport-async": "^2.0.0", "getenv": "^2.0.0", "glob": "^10.4.2", "lan-network": "^0.1.6", "minimatch": "^9.0.0", "node-forge": "^1.3.1", "npm-package-arg": "^11.0.0", "ora": "^3.4.0", "picomatch": "^3.0.1", "pretty-bytes": "^5.6.0", "pretty-format": "^29.7.0", "progress": "^2.0.3", "prompts": "^2.3.2", "qrcode-terminal": "0.11.0", "require-from-string": "^2.0.2", "requireg": "^0.2.2", "resolve": "^1.22.2", "resolve-from": "^5.0.0", "resolve.exports": "^2.0.3", "semver": "^7.6.0", "send": "^0.19.0", "slugify": "^1.3.4", "source-map-support": "~0.5.21", "stacktrace-parser": "^0.1.10", "structured-headers": "^0.4.1", "tar": "^7.4.3", "terminal-link": "^2.1.1", "undici": "^6.18.2", "wrap-ansi": "^7.0.0", "ws": "^8.12.1" }, "bin": { "expo-internal": "build/bin/cli" } }, "sha512-RDZS30OSnbXkSPnBXdyPL29KbltjOmegE23bZZDiGV23WOReWcPgRc5U7Fd8eLPhtRjHBKlBpNJMTed5Ntr/uw=="],
|
"@expo/cli": ["@expo/cli@0.24.18", "", { "dependencies": { "@0no-co/graphql.web": "^1.0.8", "@babel/runtime": "^7.20.0", "@expo/code-signing-certificates": "^0.0.5", "@expo/config": "~11.0.12", "@expo/config-plugins": "~10.1.1", "@expo/devcert": "^1.1.2", "@expo/env": "~1.0.7", "@expo/image-utils": "^0.7.6", "@expo/json-file": "^9.1.5", "@expo/metro-config": "~0.20.17", "@expo/osascript": "^2.2.5", "@expo/package-manager": "^1.8.6", "@expo/plist": "^0.3.5", "@expo/prebuild-config": "^9.0.10", "@expo/spawn-async": "^1.7.2", "@expo/ws-tunnel": "^1.0.1", "@expo/xcpretty": "^4.3.0", "@react-native/dev-middleware": "0.79.5", "@urql/core": "^5.0.6", "@urql/exchange-retry": "^1.3.0", "accepts": "^1.3.8", "arg": "^5.0.2", "better-opn": "~3.0.2", "bplist-creator": "0.1.0", "bplist-parser": "^0.3.1", "chalk": "^4.0.0", "ci-info": "^3.3.0", "compression": "^1.7.4", "connect": "^3.7.0", "debug": "^4.3.4", "env-editor": "^0.4.1", "freeport-async": "^2.0.0", "getenv": "^2.0.0", "glob": "^10.4.2", "lan-network": "^0.1.6", "minimatch": "^9.0.0", "node-forge": "^1.3.1", "npm-package-arg": "^11.0.0", "ora": "^3.4.0", "picomatch": "^3.0.1", "pretty-bytes": "^5.6.0", "pretty-format": "^29.7.0", "progress": "^2.0.3", "prompts": "^2.3.2", "qrcode-terminal": "0.11.0", "require-from-string": "^2.0.2", "requireg": "^0.2.2", "resolve": "^1.22.2", "resolve-from": "^5.0.0", "resolve.exports": "^2.0.3", "semver": "^7.6.0", "send": "^0.19.0", "slugify": "^1.3.4", "source-map-support": "~0.5.21", "stacktrace-parser": "^0.1.10", "structured-headers": "^0.4.1", "tar": "^7.4.3", "terminal-link": "^2.1.1", "undici": "^6.18.2", "wrap-ansi": "^7.0.0", "ws": "^8.12.1" }, "bin": { "expo-internal": "build/bin/cli" } }, "sha512-4cUVWa7bHS0oLn9hBCH5QKI47o+qm0JTUl8xINC0In0JIG9mlLugDSNY+t81powr28Htq9n5gOGkKPTGc1vKiw=="],
|
||||||
|
|
||||||
"@expo/code-signing-certificates": ["@expo/code-signing-certificates@0.0.5", "", { "dependencies": { "node-forge": "^1.2.1", "nullthrows": "^1.1.1" } }, "sha512-BNhXkY1bblxKZpltzAx98G2Egj9g1Q+JRcvR7E99DOj862FTCX+ZPsAUtPTr7aHxwtrL7+fL3r0JSmM9kBm+Bw=="],
|
"@expo/code-signing-certificates": ["@expo/code-signing-certificates@0.0.5", "", { "dependencies": { "node-forge": "^1.2.1", "nullthrows": "^1.1.1" } }, "sha512-BNhXkY1bblxKZpltzAx98G2Egj9g1Q+JRcvR7E99DOj862FTCX+ZPsAUtPTr7aHxwtrL7+fL3r0JSmM9kBm+Bw=="],
|
||||||
|
|
||||||
"@expo/config": ["@expo/config@11.0.10", "", { "dependencies": { "@babel/code-frame": "~7.10.4", "@expo/config-plugins": "~10.0.2", "@expo/config-types": "^53.0.4", "@expo/json-file": "^9.1.4", "deepmerge": "^4.3.1", "getenv": "^1.0.0", "glob": "^10.4.2", "require-from-string": "^2.0.2", "resolve-from": "^5.0.0", "resolve-workspace-root": "^2.0.0", "semver": "^7.6.0", "slugify": "^1.3.4", "sucrase": "3.35.0" } }, "sha512-8S8Krr/c5lnl0eF03tA2UGY9rGBhZcbWKz2UWw5dpL/+zstwUmog8oyuuC8aRcn7GiTQLlbBkxcMeT8sOGlhbA=="],
|
"@expo/config": ["@expo/config@11.0.12", "", { "dependencies": { "@babel/code-frame": "~7.10.4", "@expo/config-plugins": "~10.1.1", "@expo/config-types": "^53.0.5", "@expo/json-file": "^9.1.5", "deepmerge": "^4.3.1", "getenv": "^2.0.0", "glob": "^10.4.2", "require-from-string": "^2.0.2", "resolve-from": "^5.0.0", "resolve-workspace-root": "^2.0.0", "semver": "^7.6.0", "slugify": "^1.3.4", "sucrase": "3.35.0" } }, "sha512-XEh7g5F8OziJ6eZzBi93qt2YwmPceD3yAEd4Qv/ODK3MrgFCmB5IAJJ2ZFepdeoQFpcxS26Nl4aUuIJYEhJiUw=="],
|
||||||
|
|
||||||
"@expo/config-plugins": ["@expo/config-plugins@10.0.3", "", { "dependencies": { "@expo/config-types": "^53.0.4", "@expo/json-file": "~9.1.4", "@expo/plist": "^0.3.4", "@expo/sdk-runtime-versions": "^1.0.0", "chalk": "^4.1.2", "debug": "^4.3.5", "getenv": "^2.0.0", "glob": "^10.4.2", "resolve-from": "^5.0.0", "semver": "^7.5.4", "slash": "^3.0.0", "slugify": "^1.6.6", "xcode": "^3.0.1", "xml2js": "0.6.0" } }, "sha512-fjCckkde67pSDf48x7wRuPsgQVIqlDwN7NlOk9/DFgQ1hCH0L5pGqoSmikA1vtAyiA83MOTpkGl3F3wyATyUog=="],
|
"@expo/config-plugins": ["@expo/config-plugins@10.1.1", "", { "dependencies": { "@expo/config-types": "^53.0.5", "@expo/json-file": "~9.1.5", "@expo/plist": "^0.3.5", "@expo/sdk-runtime-versions": "^1.0.0", "chalk": "^4.1.2", "debug": "^4.3.5", "getenv": "^2.0.0", "glob": "^10.4.2", "resolve-from": "^5.0.0", "semver": "^7.5.4", "slash": "^3.0.0", "slugify": "^1.6.6", "xcode": "^3.0.1", "xml2js": "0.6.0" } }, "sha512-2L/ryY/R/AzwHfLpzBBsj0qdwN+E2RkF24uwo33L7M5DOswbLVaA007IdLlun+G6ctZYnwgm3TDLxjbvqZ9Avw=="],
|
||||||
|
|
||||||
"@expo/config-types": ["@expo/config-types@53.0.4", "", {}, "sha512-0s+9vFx83WIToEr0Iwy4CcmiUXa5BgwBmEjylBB2eojX5XAMm9mJvw9KpjAb8m7zq2G0Q6bRbeufkzgbipuNQg=="],
|
"@expo/config-types": ["@expo/config-types@53.0.5", "", {}, "sha512-kqZ0w44E+HEGBjy+Lpyn0BVL5UANg/tmNixxaRMLS6nf37YsDrLk2VMAmeKMMk5CKG0NmOdVv3ngeUjRQMsy9g=="],
|
||||||
|
|
||||||
"@expo/devcert": ["@expo/devcert@1.2.0", "", { "dependencies": { "@expo/sudo-prompt": "^9.3.1", "debug": "^3.1.0", "glob": "^10.4.2" } }, "sha512-Uilcv3xGELD5t/b0eM4cxBFEKQRIivB3v7i+VhWLV/gL98aw810unLKKJbGAxAIhY6Ipyz8ChWibFsKFXYwstA=="],
|
"@expo/devcert": ["@expo/devcert@1.2.0", "", { "dependencies": { "@expo/sudo-prompt": "^9.3.1", "debug": "^3.1.0", "glob": "^10.4.2" } }, "sha512-Uilcv3xGELD5t/b0eM4cxBFEKQRIivB3v7i+VhWLV/gL98aw810unLKKJbGAxAIhY6Ipyz8ChWibFsKFXYwstA=="],
|
||||||
|
|
||||||
"@expo/env": ["@expo/env@1.0.5", "", { "dependencies": { "chalk": "^4.0.0", "debug": "^4.3.4", "dotenv": "~16.4.5", "dotenv-expand": "~11.0.6", "getenv": "^1.0.0" } }, "sha512-dtEZ4CAMaVrFu2+tezhU3FoGWtbzQl50xV+rNJE5lYVRjUflWiZkVHlHkWUlPAwDPifLy4TuissVfScGGPWR5g=="],
|
"@expo/env": ["@expo/env@1.0.7", "", { "dependencies": { "chalk": "^4.0.0", "debug": "^4.3.4", "dotenv": "~16.4.5", "dotenv-expand": "~11.0.6", "getenv": "^2.0.0" } }, "sha512-qSTEnwvuYJ3umapO9XJtrb1fAqiPlmUUg78N0IZXXGwQRt+bkp0OBls+Y5Mxw/Owj8waAM0Z3huKKskRADR5ow=="],
|
||||||
|
|
||||||
"@expo/fingerprint": ["@expo/fingerprint@0.13.1", "", { "dependencies": { "@expo/spawn-async": "^1.7.2", "arg": "^5.0.2", "chalk": "^4.1.2", "debug": "^4.3.4", "find-up": "^5.0.0", "getenv": "^2.0.0", "glob": "^10.4.2", "ignore": "^5.3.1", "minimatch": "^9.0.0", "p-limit": "^3.1.0", "resolve-from": "^5.0.0", "semver": "^7.6.0" }, "bin": { "fingerprint": "bin/cli.js" } }, "sha512-MgZ5uIvvwAnjWeQoj4D3RnBXjD1GNOpCvhp2jtZWdQ8yEokhDEJGoHjsMT8/NCB5m2fqP5sv2V5nPzC7CN1YjQ=="],
|
"@expo/fingerprint": ["@expo/fingerprint@0.13.4", "", { "dependencies": { "@expo/spawn-async": "^1.7.2", "arg": "^5.0.2", "chalk": "^4.1.2", "debug": "^4.3.4", "find-up": "^5.0.0", "getenv": "^2.0.0", "glob": "^10.4.2", "ignore": "^5.3.1", "minimatch": "^9.0.0", "p-limit": "^3.1.0", "resolve-from": "^5.0.0", "semver": "^7.6.0" }, "bin": { "fingerprint": "bin/cli.js" } }, "sha512-MYfPYBTMfrrNr07DALuLhG6EaLVNVrY/PXjEzsjWdWE4ZFn0yqI0IdHNkJG7t1gePT8iztHc7qnsx+oo/rDo6w=="],
|
||||||
|
|
||||||
"@expo/image-utils": ["@expo/image-utils@0.7.4", "", { "dependencies": { "@expo/spawn-async": "^1.7.2", "chalk": "^4.0.0", "getenv": "^1.0.0", "jimp-compact": "0.16.1", "parse-png": "^2.1.0", "resolve-from": "^5.0.0", "semver": "^7.6.0", "temp-dir": "~2.0.0", "unique-string": "~2.0.0" } }, "sha512-LcZ82EJy/t/a1avwIboeZbO6hlw8CvsIRh2k6SWPcAOvW0RqynyKFzUJsvnjWlhUzfBEn4oI7y/Pu5Xkw3KkkA=="],
|
"@expo/image-utils": ["@expo/image-utils@0.7.6", "", { "dependencies": { "@expo/spawn-async": "^1.7.2", "chalk": "^4.0.0", "getenv": "^2.0.0", "jimp-compact": "0.16.1", "parse-png": "^2.1.0", "resolve-from": "^5.0.0", "semver": "^7.6.0", "temp-dir": "~2.0.0", "unique-string": "~2.0.0" } }, "sha512-GKnMqC79+mo/1AFrmAcUcGfbsXXTRqOMNS1umebuevl3aaw+ztsYEFEiuNhHZW7PQ3Xs3URNT513ZxKhznDscw=="],
|
||||||
|
|
||||||
"@expo/json-file": ["@expo/json-file@9.1.4", "", { "dependencies": { "@babel/code-frame": "~7.10.4", "json5": "^2.2.3" } }, "sha512-7Bv86X27fPERGhw8aJEZvRcH9sk+9BenDnEmrI3ZpywKodYSBgc8lX9Y32faNVQ/p0YbDK9zdJ0BfAKNAOyi0A=="],
|
"@expo/json-file": ["@expo/json-file@9.1.5", "", { "dependencies": { "@babel/code-frame": "~7.10.4", "json5": "^2.2.3" } }, "sha512-prWBhLUlmcQtvN6Y7BpW2k9zXGd3ySa3R6rAguMJkp1z22nunLN64KYTUWfijFlprFoxm9r2VNnGkcbndAlgKA=="],
|
||||||
|
|
||||||
"@expo/metro-config": ["@expo/metro-config@0.20.15", "", { "dependencies": { "@babel/core": "^7.20.0", "@babel/generator": "^7.20.5", "@babel/parser": "^7.20.0", "@babel/types": "^7.20.0", "@expo/config": "~11.0.10", "@expo/env": "~1.0.5", "@expo/json-file": "~9.1.4", "@expo/spawn-async": "^1.7.2", "chalk": "^4.1.0", "debug": "^4.3.2", "dotenv": "~16.4.5", "dotenv-expand": "~11.0.6", "getenv": "^2.0.0", "glob": "^10.4.2", "jsc-safe-url": "^0.2.4", "lightningcss": "~1.27.0", "minimatch": "^9.0.0", "postcss": "~8.4.32", "resolve-from": "^5.0.0" } }, "sha512-m8i58IQ7I8iOdVRfOhFmhPMHuhgeTVfQp1+mxW7URqPZaeVbuDVktPqOiNoHraKBoGPLKMUSsD+qdUuJVL3wMg=="],
|
"@expo/metro-config": ["@expo/metro-config@0.20.17", "", { "dependencies": { "@babel/core": "^7.20.0", "@babel/generator": "^7.20.5", "@babel/parser": "^7.20.0", "@babel/types": "^7.20.0", "@expo/config": "~11.0.12", "@expo/env": "~1.0.7", "@expo/json-file": "~9.1.5", "@expo/spawn-async": "^1.7.2", "chalk": "^4.1.0", "debug": "^4.3.2", "dotenv": "~16.4.5", "dotenv-expand": "~11.0.6", "getenv": "^2.0.0", "glob": "^10.4.2", "jsc-safe-url": "^0.2.4", "lightningcss": "~1.27.0", "minimatch": "^9.0.0", "postcss": "~8.4.32", "resolve-from": "^5.0.0" } }, "sha512-lpntF2UZn5bTwrPK6guUv00Xv3X9mkN3YYla+IhEHiYXWyG7WKOtDU0U4KR8h3ubkZ6SPH3snDyRyAzMsWtZFA=="],
|
||||||
|
|
||||||
"@expo/metro-runtime": ["@expo/metro-runtime@5.0.4", "", { "peerDependencies": { "react-native": "*" } }, "sha512-r694MeO+7Vi8IwOsDIDzH/Q5RPMt1kUDYbiTJwnO15nIqiDwlE8HU55UlRhffKZy6s5FmxQsZ8HA+T8DqUW8cQ=="],
|
"@expo/metro-runtime": ["@expo/metro-runtime@5.0.4", "", { "peerDependencies": { "react-native": "*" } }, "sha512-r694MeO+7Vi8IwOsDIDzH/Q5RPMt1kUDYbiTJwnO15nIqiDwlE8HU55UlRhffKZy6s5FmxQsZ8HA+T8DqUW8cQ=="],
|
||||||
|
|
||||||
"@expo/osascript": ["@expo/osascript@2.2.4", "", { "dependencies": { "@expo/spawn-async": "^1.7.2", "exec-async": "^2.2.0" } }, "sha512-Q+Oyj+1pdRiHHpev9YjqfMZzByFH8UhKvSszxa0acTveijjDhQgWrq4e9T/cchBHi0GWZpGczWyiyJkk1wM1dg=="],
|
"@expo/osascript": ["@expo/osascript@2.2.5", "", { "dependencies": { "@expo/spawn-async": "^1.7.2", "exec-async": "^2.2.0" } }, "sha512-Bpp/n5rZ0UmpBOnl7Li3LtM7la0AR3H9NNesqL+ytW5UiqV/TbonYW3rDZY38u4u/lG7TnYflVIVQPD+iqZJ5w=="],
|
||||||
|
|
||||||
"@expo/package-manager": ["@expo/package-manager@1.8.4", "", { "dependencies": { "@expo/json-file": "^9.1.4", "@expo/spawn-async": "^1.7.2", "chalk": "^4.0.0", "npm-package-arg": "^11.0.0", "ora": "^3.4.0", "resolve-workspace-root": "^2.0.0" } }, "sha512-8H8tLga/NS3iS7QaX/NneRPqbObnHvVCfMCo0ShudreOFmvmgqhYjRlkZTRstSyFqefai8ONaT4VmnLHneRYYg=="],
|
"@expo/package-manager": ["@expo/package-manager@1.8.6", "", { "dependencies": { "@expo/json-file": "^9.1.5", "@expo/spawn-async": "^1.7.2", "chalk": "^4.0.0", "npm-package-arg": "^11.0.0", "ora": "^3.4.0", "resolve-workspace-root": "^2.0.0" } }, "sha512-gcdICLuL+nHKZagPIDC5tX8UoDDB8vNA5/+SaQEqz8D+T2C4KrEJc2Vi1gPAlDnKif834QS6YluHWyxjk0yZlQ=="],
|
||||||
|
|
||||||
"@expo/plist": ["@expo/plist@0.3.4", "", { "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.2.3", "xmlbuilder": "^15.1.1" } }, "sha512-MhBLaUJNe9FQDDU2xhSNS4SAolr6K2wuyi4+A79vYuXLkAoICsbTwcGEQJN5jPY6D9izO/jsXh5k0h+mIWQMdw=="],
|
"@expo/plist": ["@expo/plist@0.3.5", "", { "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.2.3", "xmlbuilder": "^15.1.1" } }, "sha512-9RYVU1iGyCJ7vWfg3e7c/NVyMFs8wbl+dMWZphtFtsqyN9zppGREU3ctlD3i8KUE0sCUTVnLjCWr+VeUIDep2g=="],
|
||||||
|
|
||||||
"@expo/prebuild-config": ["@expo/prebuild-config@9.0.7", "", { "dependencies": { "@expo/config": "~11.0.10", "@expo/config-plugins": "~10.0.3", "@expo/config-types": "^53.0.4", "@expo/image-utils": "^0.7.4", "@expo/json-file": "^9.1.4", "@react-native/normalize-colors": "0.79.4", "debug": "^4.3.1", "resolve-from": "^5.0.0", "semver": "^7.6.0", "xml2js": "0.6.0" } }, "sha512-1w5MBp6NdF51gPGp0HsCZt0QC82hZWo37wI9HfxhdQF/sN/92Mh4t30vaY7gjHe71T5QNyab00oxZH/wP0MDgQ=="],
|
"@expo/prebuild-config": ["@expo/prebuild-config@9.0.10", "", { "dependencies": { "@expo/config": "~11.0.12", "@expo/config-plugins": "~10.1.1", "@expo/config-types": "^53.0.5", "@expo/image-utils": "^0.7.6", "@expo/json-file": "^9.1.5", "@react-native/normalize-colors": "0.79.5", "debug": "^4.3.1", "resolve-from": "^5.0.0", "semver": "^7.6.0", "xml2js": "0.6.0" } }, "sha512-lpzuel+Qb3QvGV0mnFOfeiyTq8pTGmnoGIX7p/enEgwjaCOUMSfOkbZkn6QJNAHOgNE1z5PAqzO1EBQPj2jrfA=="],
|
||||||
|
|
||||||
"@expo/sdk-runtime-versions": ["@expo/sdk-runtime-versions@1.0.0", "", {}, "sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ=="],
|
"@expo/sdk-runtime-versions": ["@expo/sdk-runtime-versions@1.0.0", "", {}, "sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ=="],
|
||||||
|
|
||||||
@@ -364,32 +367,34 @@
|
|||||||
|
|
||||||
"@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="],
|
"@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="],
|
||||||
|
|
||||||
"@react-native/assets-registry": ["@react-native/assets-registry@0.79.4", "", {}, "sha512-7PjHNRtYlc36B7P1PHme8ZV0ZJ/xsA/LvMoXe6EX++t7tSPJ8iYCMBryZhcdnztgce73b94Hfx6TTGbLF+xtUg=="],
|
"@react-native/assets-registry": ["@react-native/assets-registry@0.79.5", "", {}, "sha512-N4Kt1cKxO5zgM/BLiyzuuDNquZPiIgfktEQ6TqJ/4nKA8zr4e8KJgU6Tb2eleihDO4E24HmkvGc73naybKRz/w=="],
|
||||||
|
|
||||||
"@react-native/babel-plugin-codegen": ["@react-native/babel-plugin-codegen@0.79.4", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@react-native/codegen": "0.79.4" } }, "sha512-quhytIlDedR3ircRwifa22CaWVUVnkxccrrgztroCZaemSJM+HLurKJrjKWm0J5jV9ed+d+9Qyb1YB0syTHDjg=="],
|
"@react-native/babel-plugin-codegen": ["@react-native/babel-plugin-codegen@0.79.5", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@react-native/codegen": "0.79.5" } }, "sha512-Rt/imdfqXihD/sn0xnV4flxxb1aLLjPtMF1QleQjEhJsTUPpH4TFlfOpoCvsrXoDl4OIcB1k4FVM24Ez92zf5w=="],
|
||||||
|
|
||||||
"@react-native/babel-preset": ["@react-native/babel-preset@0.79.4", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/plugin-proposal-export-default-from": "^7.24.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-default-from": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-transform-arrow-functions": "^7.24.7", "@babel/plugin-transform-async-generator-functions": "^7.25.4", "@babel/plugin-transform-async-to-generator": "^7.24.7", "@babel/plugin-transform-block-scoping": "^7.25.0", "@babel/plugin-transform-class-properties": "^7.25.4", "@babel/plugin-transform-classes": "^7.25.4", "@babel/plugin-transform-computed-properties": "^7.24.7", "@babel/plugin-transform-destructuring": "^7.24.8", "@babel/plugin-transform-flow-strip-types": "^7.25.2", "@babel/plugin-transform-for-of": "^7.24.7", "@babel/plugin-transform-function-name": "^7.25.1", "@babel/plugin-transform-literals": "^7.25.2", "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", "@babel/plugin-transform-numeric-separator": "^7.24.7", "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-optional-catch-binding": "^7.24.7", "@babel/plugin-transform-optional-chaining": "^7.24.8", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-react-display-name": "^7.24.7", "@babel/plugin-transform-react-jsx": "^7.25.2", "@babel/plugin-transform-react-jsx-self": "^7.24.7", "@babel/plugin-transform-react-jsx-source": "^7.24.7", "@babel/plugin-transform-regenerator": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/plugin-transform-shorthand-properties": "^7.24.7", "@babel/plugin-transform-spread": "^7.24.7", "@babel/plugin-transform-sticky-regex": "^7.24.7", "@babel/plugin-transform-typescript": "^7.25.2", "@babel/plugin-transform-unicode-regex": "^7.24.7", "@babel/template": "^7.25.0", "@react-native/babel-plugin-codegen": "0.79.4", "babel-plugin-syntax-hermes-parser": "0.25.1", "babel-plugin-transform-flow-enums": "^0.0.2", "react-refresh": "^0.14.0" }, "peerDependencies": { "@babel/core": "*" } }, "sha512-El9JvYKiNfnkQ3qR7zJvvRdP3DX2i4BGYlIricWQishI3gWAfm88FQYFC2CcGoMQWJQEPN4jnDMpoISAJDEN4g=="],
|
"@react-native/babel-preset": ["@react-native/babel-preset@0.79.5", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/plugin-proposal-export-default-from": "^7.24.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-default-from": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-transform-arrow-functions": "^7.24.7", "@babel/plugin-transform-async-generator-functions": "^7.25.4", "@babel/plugin-transform-async-to-generator": "^7.24.7", "@babel/plugin-transform-block-scoping": "^7.25.0", "@babel/plugin-transform-class-properties": "^7.25.4", "@babel/plugin-transform-classes": "^7.25.4", "@babel/plugin-transform-computed-properties": "^7.24.7", "@babel/plugin-transform-destructuring": "^7.24.8", "@babel/plugin-transform-flow-strip-types": "^7.25.2", "@babel/plugin-transform-for-of": "^7.24.7", "@babel/plugin-transform-function-name": "^7.25.1", "@babel/plugin-transform-literals": "^7.25.2", "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", "@babel/plugin-transform-numeric-separator": "^7.24.7", "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-optional-catch-binding": "^7.24.7", "@babel/plugin-transform-optional-chaining": "^7.24.8", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-react-display-name": "^7.24.7", "@babel/plugin-transform-react-jsx": "^7.25.2", "@babel/plugin-transform-react-jsx-self": "^7.24.7", "@babel/plugin-transform-react-jsx-source": "^7.24.7", "@babel/plugin-transform-regenerator": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/plugin-transform-shorthand-properties": "^7.24.7", "@babel/plugin-transform-spread": "^7.24.7", "@babel/plugin-transform-sticky-regex": "^7.24.7", "@babel/plugin-transform-typescript": "^7.25.2", "@babel/plugin-transform-unicode-regex": "^7.24.7", "@babel/template": "^7.25.0", "@react-native/babel-plugin-codegen": "0.79.5", "babel-plugin-syntax-hermes-parser": "0.25.1", "babel-plugin-transform-flow-enums": "^0.0.2", "react-refresh": "^0.14.0" } }, "sha512-GDUYIWslMLbdJHEgKNfrOzXk8EDKxKzbwmBXUugoiSlr6TyepVZsj3GZDLEFarOcTwH1EXXHJsixihk8DCRQDA=="],
|
||||||
|
|
||||||
"@react-native/codegen": ["@react-native/codegen@0.79.4", "", { "dependencies": { "glob": "^7.1.1", "hermes-parser": "0.25.1", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "yargs": "^17.6.2" }, "peerDependencies": { "@babel/core": "*" } }, "sha512-K0moZDTJtqZqSs+u9tnDPSxNsdxi5irq8Nu4mzzOYlJTVNGy5H9BiIDg/NeKGfjAdo43yTDoaPSbUCvVV8cgIw=="],
|
"@react-native/codegen": ["@react-native/codegen@0.79.5", "", { "dependencies": { "glob": "^7.1.1", "hermes-parser": "0.25.1", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "yargs": "^17.6.2" }, "peerDependencies": { "@babel/core": "*" } }, "sha512-FO5U1R525A1IFpJjy+KVznEinAgcs3u7IbnbRJUG9IH/MBXi2lEU2LtN+JarJ81MCfW4V2p0pg6t/3RGHFRrlQ=="],
|
||||||
|
|
||||||
"@react-native/community-cli-plugin": ["@react-native/community-cli-plugin@0.79.4", "", { "dependencies": { "@react-native/dev-middleware": "0.79.4", "chalk": "^4.0.0", "debug": "^2.2.0", "invariant": "^2.2.4", "metro": "^0.82.0", "metro-config": "^0.82.0", "metro-core": "^0.82.0", "semver": "^7.1.3" }, "peerDependencies": { "@react-native-community/cli": "*" }, "optionalPeers": ["@react-native-community/cli"] }, "sha512-lx1RXEJwU9Tcs2B2uiDZBa6yghU6m6STvwYqHbJlFZyNN1k3JRa9j0/CDu+0fCFacIn7rEfZpb4UWi5YhsHpQg=="],
|
"@react-native/community-cli-plugin": ["@react-native/community-cli-plugin@0.79.5", "", { "dependencies": { "@react-native/dev-middleware": "0.79.5", "chalk": "^4.0.0", "debug": "^2.2.0", "invariant": "^2.2.4", "metro": "^0.82.0", "metro-config": "^0.82.0", "metro-core": "^0.82.0", "semver": "^7.1.3" }, "peerDependencies": { "@react-native-community/cli": "*" }, "optionalPeers": ["@react-native-community/cli"] }, "sha512-ApLO1ARS8JnQglqS3JAHk0jrvB+zNW3dvNJyXPZPoygBpZVbf8sjvqeBiaEYpn8ETbFWddebC4HoQelDndnrrA=="],
|
||||||
|
|
||||||
"@react-native/debugger-frontend": ["@react-native/debugger-frontend@0.79.4", "", {}, "sha512-Gg4LhxHIK86Bi2RiT1rbFAB6fuwANRsaZJ1sFZ1OZEMQEx6stEnzaIrmfgzcv4z0bTQdQ8lzCrpsz0qtdaD4eA=="],
|
"@react-native/debugger-frontend": ["@react-native/debugger-frontend@0.79.5", "", {}, "sha512-WQ49TRpCwhgUYo5/n+6GGykXmnumpOkl4Lr2l2o2buWU9qPOwoiBqJAtmWEXsAug4ciw3eLiVfthn5ufs0VB0A=="],
|
||||||
|
|
||||||
"@react-native/dev-middleware": ["@react-native/dev-middleware@0.79.4", "", { "dependencies": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.79.4", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", "debug": "^2.2.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "open": "^7.0.3", "serve-static": "^1.16.2", "ws": "^6.2.3" } }, "sha512-OWRDNkgrFEo+OSC5QKfiiBmGXKoU8gmIABK8rj2PkgwisFQ/22p7MzE5b6oB2lxWaeJT7jBX5KVniNqO46VhHA=="],
|
"@react-native/dev-middleware": ["@react-native/dev-middleware@0.79.5", "", { "dependencies": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.79.5", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", "debug": "^2.2.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "open": "^7.0.3", "serve-static": "^1.16.2", "ws": "^6.2.3" } }, "sha512-U7r9M/SEktOCP/0uS6jXMHmYjj4ESfYCkNAenBjFjjsRWekiHE+U/vRMeO+fG9gq4UCcBAUISClkQCowlftYBw=="],
|
||||||
|
|
||||||
"@react-native/gradle-plugin": ["@react-native/gradle-plugin@0.79.4", "", {}, "sha512-Gv5ryy23k7Sib2xVgqw65GTryg9YTij6URcMul5cI7LRcW0Aa1/FPb26l388P4oeNGNdDoAkkS+CuCWNunRuWg=="],
|
"@react-native/gradle-plugin": ["@react-native/gradle-plugin@0.79.5", "", {}, "sha512-K3QhfFNKiWKF3HsCZCEoWwJPSMcPJQaeqOmzFP4RL8L3nkpgUwn74PfSCcKHxooVpS6bMvJFQOz7ggUZtNVT+A=="],
|
||||||
|
|
||||||
"@react-native/js-polyfills": ["@react-native/js-polyfills@0.79.4", "", {}, "sha512-VyKPo/l9zP4+oXpQHrJq4vNOtxF7F5IMdQmceNzTnRpybRvGGgO/9jYu9mdmdKRO2KpQEc5dB4W2rYhVKdGNKg=="],
|
"@react-native/js-polyfills": ["@react-native/js-polyfills@0.79.5", "", {}, "sha512-a2wsFlIhvd9ZqCD5KPRsbCQmbZi6KxhRN++jrqG0FUTEV5vY7MvjjUqDILwJd2ZBZsf7uiDuClCcKqA+EEdbvw=="],
|
||||||
|
|
||||||
"@react-native/normalize-colors": ["@react-native/normalize-colors@0.79.4", "", {}, "sha512-247/8pHghbYY2wKjJpUsY6ZNbWcdUa5j5517LZMn6pXrbSSgWuj3JA4OYibNnocCHBaVrt+3R8XC3VEJqLlHFg=="],
|
"@react-native/normalize-colors": ["@react-native/normalize-colors@0.79.5", "", {}, "sha512-nGXMNMclZgzLUxijQQ38Dm3IAEhgxuySAWQHnljFtfB0JdaMwpe0Ox9H7Tp2OgrEA+EMEv+Od9ElKlHwGKmmvQ=="],
|
||||||
|
|
||||||
"@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.79.4", "", { "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "peerDependencies": { "@types/react": "^19.0.0", "react": "*", "react-native": "*" } }, "sha512-0Mdcox6e5PTonuM1WIo3ks7MBAa3IDzj0pKnE5xAwSgQ0DJW2P5dYf+KjWmpkE+Yb0w41ZbtXPhKq+U2JJ6C/Q=="],
|
"@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.79.5", "", { "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "peerDependencies": { "@types/react": "^19.0.0", "react": "*", "react-native": "*" }, "optionalPeers": ["@types/react"] }, "sha512-EUPM2rfGNO4cbI3olAbhPkIt3q7MapwCwAJBzUfWlZ/pu0PRNOnMQ1IvaXTf3TpeozXV52K1OdprLEI/kI5eUA=="],
|
||||||
|
|
||||||
"@react-navigation/bottom-tabs": ["@react-navigation/bottom-tabs@7.4.2", "", { "dependencies": { "@react-navigation/elements": "^2.5.2", "color": "^4.2.3" }, "peerDependencies": { "@react-navigation/native": "^7.1.14", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", "react-native-screens": ">= 4.0.0" } }, "sha512-jyBux5l3qqEucY5M/ZWxVvfA8TQu7DVl2gK+xB6iKqRUfLf7dSumyVxc7HemDwGFoz3Ug8dVZFvSMEs+mfrieQ=="],
|
"@react-navigation/bottom-tabs": ["@react-navigation/bottom-tabs@7.4.2", "", { "dependencies": { "@react-navigation/elements": "^2.5.2", "color": "^4.2.3" }, "peerDependencies": { "@react-navigation/native": "^7.1.14", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", "react-native-screens": ">= 4.0.0" } }, "sha512-jyBux5l3qqEucY5M/ZWxVvfA8TQu7DVl2gK+xB6iKqRUfLf7dSumyVxc7HemDwGFoz3Ug8dVZFvSMEs+mfrieQ=="],
|
||||||
|
|
||||||
"@react-navigation/core": ["@react-navigation/core@7.11.0", "", { "dependencies": { "@react-navigation/routers": "^7.4.1", "escape-string-regexp": "^4.0.0", "nanoid": "^3.3.11", "query-string": "^7.1.3", "react-is": "^19.1.0", "use-latest-callback": "^0.2.4", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": ">= 18.2.0" } }, "sha512-LfYPtxsMjldJ80BBeedaDCN0LE81WU1NP4V9Ia3wSrCPTAXt11y6holaBUrmUMVQVqpEyPRQrjwrT1QkfGKquw=="],
|
"@react-navigation/core": ["@react-navigation/core@7.11.0", "", { "dependencies": { "@react-navigation/routers": "^7.4.1", "escape-string-regexp": "^4.0.0", "nanoid": "^3.3.11", "query-string": "^7.1.3", "react-is": "^19.1.0", "use-latest-callback": "^0.2.4", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": ">= 18.2.0" } }, "sha512-LfYPtxsMjldJ80BBeedaDCN0LE81WU1NP4V9Ia3wSrCPTAXt11y6holaBUrmUMVQVqpEyPRQrjwrT1QkfGKquw=="],
|
||||||
|
|
||||||
|
"@react-navigation/drawer": ["@react-navigation/drawer@7.5.2", "", { "dependencies": { "@react-navigation/elements": "^2.5.2", "color": "^4.2.3", "react-native-drawer-layout": "^4.1.11", "use-latest-callback": "^0.2.4" }, "peerDependencies": { "@react-navigation/native": "^7.1.14", "react": ">= 18.2.0", "react-native": "*", "react-native-gesture-handler": ">= 2.0.0", "react-native-reanimated": ">= 2.0.0", "react-native-safe-area-context": ">= 4.0.0", "react-native-screens": ">= 4.0.0" } }, "sha512-1FSo+DyJe2zlIcQBhHcayZCe2aAF2JF+rpn7HnVnTV2HaCEpgJ0/zgHIa9MZByKntp/aSexL9YkDFQhQj2+7ag=="],
|
||||||
|
|
||||||
"@react-navigation/elements": ["@react-navigation/elements@2.4.5", "", { "dependencies": { "color": "^4.2.3", "use-latest-callback": "^0.2.4" }, "peerDependencies": { "@react-native-masked-view/masked-view": ">= 0.2.0", "@react-navigation/native": "^7.1.12", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0" }, "optionalPeers": ["@react-native-masked-view/masked-view"] }, "sha512-rzoQQ07dZGA3h608imB1nAZ2rPw9vZ2xc2K36XSZoV/7IZRDxI4BCIj38Wc4saQaYhfJIoeVssK4+6IwhZBedg=="],
|
"@react-navigation/elements": ["@react-navigation/elements@2.4.5", "", { "dependencies": { "color": "^4.2.3", "use-latest-callback": "^0.2.4" }, "peerDependencies": { "@react-native-masked-view/masked-view": ">= 0.2.0", "@react-navigation/native": "^7.1.12", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0" }, "optionalPeers": ["@react-native-masked-view/masked-view"] }, "sha512-rzoQQ07dZGA3h608imB1nAZ2rPw9vZ2xc2K36XSZoV/7IZRDxI4BCIj38Wc4saQaYhfJIoeVssK4+6IwhZBedg=="],
|
||||||
|
|
||||||
"@react-navigation/native": ["@react-navigation/native@7.1.12", "", { "dependencies": { "@react-navigation/core": "^7.11.0", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", "nanoid": "^3.3.11", "use-latest-callback": "^0.2.4" }, "peerDependencies": { "react": ">= 18.2.0", "react-native": "*" } }, "sha512-ezHzrZN+9SE4Co6/H8MgDWlBxfJbVc5xi8szRi2QW8eJlsZsAvgGqtKs4YECraV4Yr9zW8RCzNuUxYiQiPMtEQ=="],
|
"@react-navigation/native": ["@react-navigation/native@7.1.12", "", { "dependencies": { "@react-navigation/core": "^7.11.0", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", "nanoid": "^3.3.11", "use-latest-callback": "^0.2.4" }, "peerDependencies": { "react": ">= 18.2.0", "react-native": "*" } }, "sha512-ezHzrZN+9SE4Co6/H8MgDWlBxfJbVc5xi8szRi2QW8eJlsZsAvgGqtKs4YECraV4Yr9zW8RCzNuUxYiQiPMtEQ=="],
|
||||||
@@ -586,7 +591,7 @@
|
|||||||
|
|
||||||
"babel-preset-current-node-syntax": ["babel-preset-current-node-syntax@1.1.0", "", { "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-import-attributes": "^7.24.7", "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-numeric-separator": "^7.10.4", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw=="],
|
"babel-preset-current-node-syntax": ["babel-preset-current-node-syntax@1.1.0", "", { "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-import-attributes": "^7.24.7", "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-numeric-separator": "^7.10.4", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw=="],
|
||||||
|
|
||||||
"babel-preset-expo": ["babel-preset-expo@13.2.1", "", { "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/plugin-proposal-decorators": "^7.12.9", "@babel/plugin-proposal-export-default-from": "^7.24.7", "@babel/plugin-syntax-export-default-from": "^7.24.7", "@babel/plugin-transform-export-namespace-from": "^7.25.9", "@babel/plugin-transform-flow-strip-types": "^7.25.2", "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/preset-react": "^7.22.15", "@babel/preset-typescript": "^7.23.0", "@react-native/babel-preset": "0.79.4", "babel-plugin-react-native-web": "~0.19.13", "babel-plugin-syntax-hermes-parser": "^0.25.1", "babel-plugin-transform-flow-enums": "^0.0.2", "debug": "^4.3.4", "react-refresh": "^0.14.2", "resolve-from": "^5.0.0" }, "peerDependencies": { "babel-plugin-react-compiler": "^19.0.0-beta-e993439-20250405" }, "optionalPeers": ["babel-plugin-react-compiler"] }, "sha512-Ol3w0uLJNQ5tDfCf4L+IDTDMgJkVMQHhvYqMxs18Ib0DcaBQIfE8mneSSk7FcuI6FS0phw/rZhoEquQh1/Q3wA=="],
|
"babel-preset-expo": ["babel-preset-expo@13.2.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/plugin-proposal-decorators": "^7.12.9", "@babel/plugin-proposal-export-default-from": "^7.24.7", "@babel/plugin-syntax-export-default-from": "^7.24.7", "@babel/plugin-transform-export-namespace-from": "^7.25.9", "@babel/plugin-transform-flow-strip-types": "^7.25.2", "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/preset-react": "^7.22.15", "@babel/preset-typescript": "^7.23.0", "@react-native/babel-preset": "0.79.5", "babel-plugin-react-native-web": "~0.19.13", "babel-plugin-syntax-hermes-parser": "^0.25.1", "babel-plugin-transform-flow-enums": "^0.0.2", "debug": "^4.3.4", "react-refresh": "^0.14.2", "resolve-from": "^5.0.0" }, "peerDependencies": { "babel-plugin-react-compiler": "^19.0.0-beta-e993439-20250405" }, "optionalPeers": ["babel-plugin-react-compiler"] }, "sha512-wQJn92lqj8GKR7Ojg/aW4+GkqI6ZdDNTDyOqhhl7A9bAqk6t0ukUOWLDXQb4p0qKJjMDV1F6gNWasI2KUbuVTQ=="],
|
||||||
|
|
||||||
"babel-preset-jest": ["babel-preset-jest@29.6.3", "", { "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA=="],
|
"babel-preset-jest": ["babel-preset-jest@29.6.3", "", { "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA=="],
|
||||||
|
|
||||||
@@ -802,39 +807,45 @@
|
|||||||
|
|
||||||
"exec-async": ["exec-async@2.2.0", "", {}, "sha512-87OpwcEiMia/DeiKFzaQNBNFeN3XkkpYIh9FyOqq5mS2oKv3CBE67PXoEKcr6nodWdXNogTiQ0jE2NGuoffXPw=="],
|
"exec-async": ["exec-async@2.2.0", "", {}, "sha512-87OpwcEiMia/DeiKFzaQNBNFeN3XkkpYIh9FyOqq5mS2oKv3CBE67PXoEKcr6nodWdXNogTiQ0jE2NGuoffXPw=="],
|
||||||
|
|
||||||
"expo": ["expo@53.0.12", "", { "dependencies": { "@babel/runtime": "^7.20.0", "@expo/cli": "0.24.15", "@expo/config": "~11.0.10", "@expo/config-plugins": "~10.0.3", "@expo/fingerprint": "0.13.1", "@expo/metro-config": "0.20.15", "@expo/vector-icons": "^14.0.0", "babel-preset-expo": "~13.2.1", "expo-asset": "~11.1.5", "expo-constants": "~17.1.6", "expo-file-system": "~18.1.10", "expo-font": "~13.3.1", "expo-keep-awake": "~14.1.4", "expo-modules-autolinking": "2.1.12", "expo-modules-core": "2.4.0", "react-native-edge-to-edge": "1.6.0", "whatwg-url-without-unicode": "8.0.0-3" }, "peerDependencies": { "@expo/dom-webview": "*", "@expo/metro-runtime": "*", "react": "*", "react-native": "*", "react-native-webview": "*" }, "optionalPeers": ["@expo/dom-webview"], "bin": { "expo": "bin/cli", "expo-modules-autolinking": "bin/autolinking", "fingerprint": "bin/fingerprint" } }, "sha512-dtmED749hkxDWCcvtD++tb8bAm3Twv8qnUOXzVyXA5owNG0mwDIz0HveJTpWK1UzkY4HcTVRezDf0tflZJ+JXQ=="],
|
"expo": ["expo@53.0.17", "", { "dependencies": { "@babel/runtime": "^7.20.0", "@expo/cli": "0.24.18", "@expo/config": "~11.0.12", "@expo/config-plugins": "~10.1.1", "@expo/fingerprint": "0.13.4", "@expo/metro-config": "0.20.17", "@expo/vector-icons": "^14.0.0", "babel-preset-expo": "~13.2.3", "expo-asset": "~11.1.7", "expo-constants": "~17.1.7", "expo-file-system": "~18.1.11", "expo-font": "~13.3.2", "expo-keep-awake": "~14.1.4", "expo-modules-autolinking": "2.1.13", "expo-modules-core": "2.4.2", "react-native-edge-to-edge": "1.6.0", "whatwg-url-without-unicode": "8.0.0-3" }, "peerDependencies": { "@expo/dom-webview": "*", "@expo/metro-runtime": "*", "react": "*", "react-native": "*", "react-native-webview": "*" }, "optionalPeers": ["@expo/dom-webview", "@expo/metro-runtime", "react-native-webview"], "bin": { "expo": "bin/cli", "fingerprint": "bin/fingerprint", "expo-modules-autolinking": "bin/autolinking" } }, "sha512-I1z4X/BoirQeWH8VMcfW1N3OsKCY0LslGjhzDsBWomv4rzviLkcm7KNJBeYWddY7wGo0bljT8S57NGsIJS/f9g=="],
|
||||||
|
|
||||||
"expo-asset": ["expo-asset@11.1.5", "", { "dependencies": { "@expo/image-utils": "^0.7.4", "expo-constants": "~17.1.5" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-GEQDCqC25uDBoXHEnXeBuwpeXvI+3fRGvtzwwt0ZKKzWaN+TgeF8H7c76p3Zi4DfBMFDcduM0CmOvJX+yCCLUQ=="],
|
"expo-asset": ["expo-asset@11.1.7", "", { "dependencies": { "@expo/image-utils": "^0.7.6", "expo-constants": "~17.1.7" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-b5P8GpjUh08fRCf6m5XPVAh7ra42cQrHBIMgH2UXP+xsj4Wufl6pLy6jRF5w6U7DranUMbsXm8TOyq4EHy7ADg=="],
|
||||||
|
|
||||||
"expo-blur": ["expo-blur@14.1.5", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-CCLJHxN4eoAl06ESKT3CbMasJ98WsjF9ZQEJnuxtDb9ffrYbZ+g9ru84fukjNUOTtc8A8yXE5z8NgY1l0OMrmQ=="],
|
"expo-blur": ["expo-blur@14.1.5", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-CCLJHxN4eoAl06ESKT3CbMasJ98WsjF9ZQEJnuxtDb9ffrYbZ+g9ru84fukjNUOTtc8A8yXE5z8NgY1l0OMrmQ=="],
|
||||||
|
|
||||||
"expo-constants": ["expo-constants@17.1.6", "", { "dependencies": { "@expo/config": "~11.0.9", "@expo/env": "~1.0.5" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-q5mLvJiLtPcaZ7t2diSOlQ2AyxIO8YMVEJsEfI/ExkGj15JrflNQ7CALEW6IF/uNae/76qI/XcjEuuAyjdaCNw=="],
|
"expo-camera": ["expo-camera@16.1.10", "", { "dependencies": { "invariant": "^2.2.4" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*", "react-native-web": "*" }, "optionalPeers": ["react-native-web"] }, "sha512-qoRJeSwPmMbuu0VfnQTC+q79Kt2SqTWColEImgithL9u0qUQcC55U89IfhZk55Hpt6f1DgKuDzUOG5oY+snSWg=="],
|
||||||
|
|
||||||
"expo-file-system": ["expo-file-system@18.1.10", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-SyaWg+HitScLuyEeSG9gMSDT0hIxbM9jiZjSBP9l9zMnwZjmQwsusE6+7qGiddxJzdOhTP4YGUfvEzeeS0YL3Q=="],
|
"expo-constants": ["expo-constants@17.1.7", "", { "dependencies": { "@expo/config": "~11.0.12", "@expo/env": "~1.0.7" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-byBjGsJ6T6FrLlhOBxw4EaiMXrZEn/MlUYIj/JAd+FS7ll5X/S4qVRbIimSJtdW47hXMq0zxPfJX6njtA56hHA=="],
|
||||||
|
|
||||||
"expo-font": ["expo-font@13.3.1", "", { "dependencies": { "fontfaceobserver": "^2.1.0" }, "peerDependencies": { "expo": "*", "react": "*" } }, "sha512-d+xrHYvSM9WB42wj8vP9OOFWyxed5R1evphfDb6zYBmC1dA9Hf89FpT7TNFtj2Bk3clTnpmVqQTCYbbA2P3CLg=="],
|
"expo-file-system": ["expo-file-system@18.1.11", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-HJw/m0nVOKeqeRjPjGdvm+zBi5/NxcdPf8M8P3G2JFvH5Z8vBWqVDic2O58jnT1OFEy0XXzoH9UqFu7cHg9DTQ=="],
|
||||||
|
|
||||||
|
"expo-font": ["expo-font@13.3.2", "", { "dependencies": { "fontfaceobserver": "^2.1.0" }, "peerDependencies": { "expo": "*", "react": "*" } }, "sha512-wUlMdpqURmQ/CNKK/+BIHkDA5nGjMqNlYmW0pJFXY/KE/OG80Qcavdu2sHsL4efAIiNGvYdBS10WztuQYU4X0A=="],
|
||||||
|
|
||||||
"expo-haptics": ["expo-haptics@14.1.4", "", { "peerDependencies": { "expo": "*" } }, "sha512-QZdE3NMX74rTuIl82I+n12XGwpDWKb8zfs5EpwsnGi/D/n7O2Jd4tO5ivH+muEG/OCJOMq5aeaVDqqaQOhTkcA=="],
|
"expo-haptics": ["expo-haptics@14.1.4", "", { "peerDependencies": { "expo": "*" } }, "sha512-QZdE3NMX74rTuIl82I+n12XGwpDWKb8zfs5EpwsnGi/D/n7O2Jd4tO5ivH+muEG/OCJOMq5aeaVDqqaQOhTkcA=="],
|
||||||
|
|
||||||
"expo-image": ["expo-image@2.3.0", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*", "react-native-web": "*" } }, "sha512-muL8OSbgCskQJsyqenKPNULWXwRm5BY2ruS6WMo/EzFyI3iXI/0mXgb2J/NXUa8xCEYxSyoGkGZFyCBvGY1ofA=="],
|
"expo-image": ["expo-image@2.3.2", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*", "react-native-web": "*" }, "optionalPeers": ["react-native-web"] }, "sha512-TOp7UR1mzeCxzs3c/6MV2Wy7jBfJpKq8aVC06gkLfxHsCVMeGqCXc+6GMrGIVrjG938LEub4dwnrE0OuSE2Qwg=="],
|
||||||
|
|
||||||
|
"expo-image-loader": ["expo-image-loader@5.1.0", "", { "peerDependencies": { "expo": "*" } }, "sha512-sEBx3zDQIODWbB5JwzE7ZL5FJD+DK3LVLWBVJy6VzsqIA6nDEnSFnsnWyCfCTSvbGigMATs1lgkC2nz3Jpve1Q=="],
|
||||||
|
|
||||||
|
"expo-image-picker": ["expo-image-picker@16.1.4", "", { "dependencies": { "expo-image-loader": "~5.1.0" }, "peerDependencies": { "expo": "*" } }, "sha512-bTmmxtw1AohUT+HxEBn2vYwdeOrj1CLpMXKjvi9FKSoSbpcarT4xxI0z7YyGwDGHbrJqyyic3I9TTdP2J2b4YA=="],
|
||||||
|
|
||||||
"expo-keep-awake": ["expo-keep-awake@14.1.4", "", { "peerDependencies": { "expo": "*", "react": "*" } }, "sha512-wU9qOnosy4+U4z/o4h8W9PjPvcFMfZXrlUoKTMBW7F4pLqhkkP/5G4EviPZixv4XWFMjn1ExQ5rV6BX8GwJsWA=="],
|
"expo-keep-awake": ["expo-keep-awake@14.1.4", "", { "peerDependencies": { "expo": "*", "react": "*" } }, "sha512-wU9qOnosy4+U4z/o4h8W9PjPvcFMfZXrlUoKTMBW7F4pLqhkkP/5G4EviPZixv4XWFMjn1ExQ5rV6BX8GwJsWA=="],
|
||||||
|
|
||||||
"expo-linking": ["expo-linking@7.1.5", "", { "dependencies": { "expo-constants": "~17.1.6", "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-8g20zOpROW78bF+bLI4a3ZWj4ntLgM0rCewKycPL0jk9WGvBrBtFtwwADJgOiV1EurNp3lcquerXGlWS+SOQyA=="],
|
"expo-linking": ["expo-linking@7.1.7", "", { "dependencies": { "expo-constants": "~17.1.7", "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-ZJaH1RIch2G/M3hx2QJdlrKbYFUTOjVVW4g39hfxrE5bPX9xhZUYXqxqQtzMNl1ylAevw9JkgEfWbBWddbZ3UA=="],
|
||||||
|
|
||||||
"expo-modules-autolinking": ["expo-modules-autolinking@2.1.12", "", { "dependencies": { "@expo/spawn-async": "^1.7.2", "chalk": "^4.1.0", "commander": "^7.2.0", "find-up": "^5.0.0", "glob": "^10.4.2", "require-from-string": "^2.0.2", "resolve-from": "^5.0.0" }, "bin": "bin/expo-modules-autolinking.js" }, "sha512-rW5YSW66pUx1nLqn7TO0eWRnP4LDvySW1Tom0wjexk3Tx/upg9LYE5tva7p5AX/cdFfiZcEqPcOxP4RyT++Xlg=="],
|
"expo-modules-autolinking": ["expo-modules-autolinking@2.1.13", "", { "dependencies": { "@expo/spawn-async": "^1.7.2", "chalk": "^4.1.0", "commander": "^7.2.0", "find-up": "^5.0.0", "glob": "^10.4.2", "require-from-string": "^2.0.2", "resolve-from": "^5.0.0" }, "bin": { "expo-modules-autolinking": "bin/expo-modules-autolinking.js" } }, "sha512-+SaiYkdP3LXOFm/26CHMHBof9Xq/0MHNDzL/K0OwPgHLhZ6wpDWIDYWRHNueWYtGpAeLw2XAhR0HX4FNtU09qw=="],
|
||||||
|
|
||||||
"expo-modules-core": ["expo-modules-core@2.4.0", "", { "dependencies": { "invariant": "^2.2.4" } }, "sha512-Ko5eHBdvuMykjw9P9C9PF54/wBSsGOxaOjx92I5BwgKvEmUwN3UrXFV4CXzlLVbLfSYUQaLcB220xmPfgvT7Fg=="],
|
"expo-modules-core": ["expo-modules-core@2.4.2", "", { "dependencies": { "invariant": "^2.2.4" } }, "sha512-RCb0wniYCJkxwpXrkiBA/WiNGxzYsEpL0sB50gTnS/zEfX3DImS2npc4lfZ3hPZo1UF9YC6OSI9Do+iacV0NUg=="],
|
||||||
|
|
||||||
"expo-router": ["expo-router@5.1.0", "", { "dependencies": { "@expo/metro-runtime": "5.0.4", "@expo/server": "^0.6.2", "@radix-ui/react-slot": "1.2.0", "@react-navigation/bottom-tabs": "^7.3.10", "@react-navigation/native": "^7.1.6", "@react-navigation/native-stack": "^7.3.10", "client-only": "^0.0.1", "invariant": "^2.2.4", "react-fast-compare": "^3.2.2", "react-native-is-edge-to-edge": "^1.1.6", "schema-utils": "^4.0.1", "semver": "~7.6.3", "server-only": "^0.0.1", "shallowequal": "^1.1.0" }, "peerDependencies": { "@react-navigation/drawer": "^7.3.9", "expo": "*", "expo-constants": "*", "expo-linking": "*", "react-native-reanimated": "*", "react-native-safe-area-context": "*", "react-native-screens": "*" }, "optionalPeers": ["@react-navigation/drawer"] }, "sha512-mnKpw35W6kKPpZm+ZxQei6HGUx2JO3znzqJZInzqrTZMgfAcHGgvP9AQFjg/Qi/Qy1CxunB9aQnqE9JPbSwbpw=="],
|
"expo-router": ["expo-router@5.1.3", "", { "dependencies": { "@expo/metro-runtime": "5.0.4", "@expo/server": "^0.6.3", "@radix-ui/react-slot": "1.2.0", "@react-navigation/bottom-tabs": "^7.3.10", "@react-navigation/native": "^7.1.6", "@react-navigation/native-stack": "^7.3.10", "client-only": "^0.0.1", "invariant": "^2.2.4", "react-fast-compare": "^3.2.2", "react-native-is-edge-to-edge": "^1.1.6", "schema-utils": "^4.0.1", "semver": "~7.6.3", "server-only": "^0.0.1", "shallowequal": "^1.1.0" }, "peerDependencies": { "@react-navigation/drawer": "^7.3.9", "expo": "*", "expo-constants": "*", "expo-linking": "*", "react-native-reanimated": "*", "react-native-safe-area-context": "*", "react-native-screens": "*" }, "optionalPeers": ["@react-navigation/drawer", "react-native-reanimated"] }, "sha512-zoAU0clwEj569PpGOzc06wCcxOskHLEyonJhLNPsweJgu+vE010d6XW+yr5ODR6F3ViFJpfcjbe7u3SaTjl24Q=="],
|
||||||
|
|
||||||
"expo-splash-screen": ["expo-splash-screen@0.30.9", "", { "dependencies": { "@expo/prebuild-config": "^9.0.6" }, "peerDependencies": { "expo": "*" } }, "sha512-curHUaZxUTZ2dWvz32ao3xPv5mJr1LBqn5V8xm/IULAehB9RGCn8iKiROMN1PYebSG+56vPMuJmBm9P+ayvJpA=="],
|
"expo-splash-screen": ["expo-splash-screen@0.30.10", "", { "dependencies": { "@expo/prebuild-config": "^9.0.10" }, "peerDependencies": { "expo": "*" } }, "sha512-Tt9va/sLENQDQYeOQ6cdLdGvTZ644KR3YG9aRlnpcs2/beYjOX1LHT510EGzVN9ljUTg+1ebEo5GGt2arYtPjw=="],
|
||||||
|
|
||||||
"expo-status-bar": ["expo-status-bar@2.2.3", "", { "dependencies": { "react-native-edge-to-edge": "1.6.0", "react-native-is-edge-to-edge": "^1.1.6" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-+c8R3AESBoduunxTJ8353SqKAKpxL6DvcD8VKBuh81zzJyUUbfB4CVjr1GufSJEKsMzNPXZU+HJwXx7Xh7lx8Q=="],
|
"expo-status-bar": ["expo-status-bar@2.2.3", "", { "dependencies": { "react-native-edge-to-edge": "1.6.0", "react-native-is-edge-to-edge": "^1.1.6" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-+c8R3AESBoduunxTJ8353SqKAKpxL6DvcD8VKBuh81zzJyUUbfB4CVjr1GufSJEKsMzNPXZU+HJwXx7Xh7lx8Q=="],
|
||||||
|
|
||||||
"expo-symbols": ["expo-symbols@0.4.5", "", { "dependencies": { "sf-symbols-typescript": "^2.0.0" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-ZbgvJfACPfWaJxJrUd0YzDmH9X0Ci7vb5m0/ZpDz/tnF1vQJlkovvpFEHLUmCDSLIN7/fNK8t696KSpzfm8/kg=="],
|
"expo-symbols": ["expo-symbols@0.4.5", "", { "dependencies": { "sf-symbols-typescript": "^2.0.0" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-ZbgvJfACPfWaJxJrUd0YzDmH9X0Ci7vb5m0/ZpDz/tnF1vQJlkovvpFEHLUmCDSLIN7/fNK8t696KSpzfm8/kg=="],
|
||||||
|
|
||||||
"expo-system-ui": ["expo-system-ui@5.0.9", "", { "dependencies": { "@react-native/normalize-colors": "0.79.4", "debug": "^4.3.2" }, "peerDependencies": { "expo": "*", "react-native": "*", "react-native-web": "*" } }, "sha512-behQ4uP384++U9GjgXmyEno1Z8raN1/tZv7ZJhYkQkRj1g2xXvNltXN/PDRcOm/wCNqStVhDpYo2OOQm5E5/lQ=="],
|
"expo-system-ui": ["expo-system-ui@5.0.10", "", { "dependencies": { "@react-native/normalize-colors": "0.79.5", "debug": "^4.3.2" }, "peerDependencies": { "expo": "*", "react-native": "*", "react-native-web": "*" }, "optionalPeers": ["react-native-web"] }, "sha512-BTXbSyJr80yuN6VO4XQKZj7BjesZQLHgOYZ0bWyf4VB19GFZq7ZnZOEc/eoKk1B3eIocOMKUfNCrg/Wn8Kfcuw=="],
|
||||||
|
|
||||||
"expo-web-browser": ["expo-web-browser@14.2.0", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-6S51d8pVlDRDsgGAp8BPpwnxtyKiMWEFdezNz+5jVIyT+ctReW42uxnjRgtsdn5sXaqzhaX+Tzk/CWaKCyC0hw=="],
|
"expo-web-browser": ["expo-web-browser@14.2.0", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-6S51d8pVlDRDsgGAp8BPpwnxtyKiMWEFdezNz+5jVIyT+ctReW42uxnjRgtsdn5sXaqzhaX+Tzk/CWaKCyC0hw=="],
|
||||||
|
|
||||||
@@ -1348,10 +1359,12 @@
|
|||||||
|
|
||||||
"react-is": ["react-is@19.1.0", "", {}, "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg=="],
|
"react-is": ["react-is@19.1.0", "", {}, "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg=="],
|
||||||
|
|
||||||
"react-native": ["react-native@0.79.4", "", { "dependencies": { "@jest/create-cache-key-function": "^29.7.0", "@react-native/assets-registry": "0.79.4", "@react-native/codegen": "0.79.4", "@react-native/community-cli-plugin": "0.79.4", "@react-native/gradle-plugin": "0.79.4", "@react-native/js-polyfills": "0.79.4", "@react-native/normalize-colors": "0.79.4", "@react-native/virtualized-lists": "0.79.4", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", "babel-jest": "^29.7.0", "babel-plugin-syntax-hermes-parser": "0.25.1", "base64-js": "^1.5.1", "chalk": "^4.0.0", "commander": "^12.0.0", "event-target-shim": "^5.0.1", "flow-enums-runtime": "^0.0.6", "glob": "^7.1.1", "invariant": "^2.2.4", "jest-environment-node": "^29.7.0", "memoize-one": "^5.0.0", "metro-runtime": "^0.82.0", "metro-source-map": "^0.82.0", "nullthrows": "^1.1.1", "pretty-format": "^29.7.0", "promise": "^8.3.0", "react-devtools-core": "^6.1.1", "react-refresh": "^0.14.0", "regenerator-runtime": "^0.13.2", "scheduler": "0.25.0", "semver": "^7.1.3", "stacktrace-parser": "^0.1.10", "whatwg-fetch": "^3.0.0", "ws": "^6.2.3", "yargs": "^17.6.2" }, "peerDependencies": { "@types/react": "^19.0.0", "react": "^19.0.0" }, "bin": "cli.js" }, "sha512-CfxYMuszvnO/33Q5rB//7cU1u9P8rSOvzhE2053Phdb8+6bof9NLayCllU2nmPrm8n9o6RU1Fz5H0yquLQ0DAw=="],
|
"react-native": ["react-native@0.79.5", "", { "dependencies": { "@jest/create-cache-key-function": "^29.7.0", "@react-native/assets-registry": "0.79.5", "@react-native/codegen": "0.79.5", "@react-native/community-cli-plugin": "0.79.5", "@react-native/gradle-plugin": "0.79.5", "@react-native/js-polyfills": "0.79.5", "@react-native/normalize-colors": "0.79.5", "@react-native/virtualized-lists": "0.79.5", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", "babel-jest": "^29.7.0", "babel-plugin-syntax-hermes-parser": "0.25.1", "base64-js": "^1.5.1", "chalk": "^4.0.0", "commander": "^12.0.0", "event-target-shim": "^5.0.1", "flow-enums-runtime": "^0.0.6", "glob": "^7.1.1", "invariant": "^2.2.4", "jest-environment-node": "^29.7.0", "memoize-one": "^5.0.0", "metro-runtime": "^0.82.0", "metro-source-map": "^0.82.0", "nullthrows": "^1.1.1", "pretty-format": "^29.7.0", "promise": "^8.3.0", "react-devtools-core": "^6.1.1", "react-refresh": "^0.14.0", "regenerator-runtime": "^0.13.2", "scheduler": "0.25.0", "semver": "^7.1.3", "stacktrace-parser": "^0.1.10", "whatwg-fetch": "^3.0.0", "ws": "^6.2.3", "yargs": "^17.6.2" }, "peerDependencies": { "@types/react": "^19.0.0", "react": "^19.0.0" }, "optionalPeers": ["@types/react"], "bin": { "react-native": "cli.js" } }, "sha512-jVihwsE4mWEHZ9HkO1J2eUZSwHyDByZOqthwnGrVZCh6kTQBCm4v8dicsyDa6p0fpWNE5KicTcpX/XXl0ASJFg=="],
|
||||||
|
|
||||||
"react-native-country-codes-picker": ["react-native-country-codes-picker@2.3.5", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-dDQhd0bVvlmgb84NPhTOmTk5UVYPHtk3lqZI+BPb61H1rC2IDrTvPWENg6u1DMGliqWHQDBYpeH37zvxxQL71w=="],
|
"react-native-country-codes-picker": ["react-native-country-codes-picker@2.3.5", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-dDQhd0bVvlmgb84NPhTOmTk5UVYPHtk3lqZI+BPb61H1rC2IDrTvPWENg6u1DMGliqWHQDBYpeH37zvxxQL71w=="],
|
||||||
|
|
||||||
|
"react-native-drawer-layout": ["react-native-drawer-layout@4.1.11", "", { "dependencies": { "use-latest-callback": "^0.2.4" }, "peerDependencies": { "react": ">= 18.2.0", "react-native": "*", "react-native-gesture-handler": ">= 2.0.0", "react-native-reanimated": ">= 2.0.0" } }, "sha512-31gilubSKPLToy31/bb0hhgOOenHYJq4JC7g/JkIEqBqSWzoCgiOlccDHlBRG+MV37UtXZnJN2spj3VusdCd4A=="],
|
||||||
|
|
||||||
"react-native-edge-to-edge": ["react-native-edge-to-edge@1.6.0", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-2WCNdE3Qd6Fwg9+4BpbATUxCLcouF6YRY7K+J36KJ4l3y+tWN6XCqAC4DuoGblAAbb2sLkhEDp4FOlbOIot2Og=="],
|
"react-native-edge-to-edge": ["react-native-edge-to-edge@1.6.0", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-2WCNdE3Qd6Fwg9+4BpbATUxCLcouF6YRY7K+J36KJ4l3y+tWN6XCqAC4DuoGblAAbb2sLkhEDp4FOlbOIot2Og=="],
|
||||||
|
|
||||||
"react-native-gesture-handler": ["react-native-gesture-handler@2.24.0", "", { "dependencies": { "@egjs/hammerjs": "^2.0.17", "hoist-non-react-statics": "^3.3.0", "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-ZdWyOd1C8axKJHIfYxjJKCcxjWEpUtUWgTOVY2wynbiveSQDm8X/PDyAKXSer/GOtIpjudUbACOndZXCN3vHsw=="],
|
"react-native-gesture-handler": ["react-native-gesture-handler@2.24.0", "", { "dependencies": { "@egjs/hammerjs": "^2.0.17", "hoist-non-react-statics": "^3.3.0", "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-ZdWyOd1C8axKJHIfYxjJKCcxjWEpUtUWgTOVY2wynbiveSQDm8X/PDyAKXSer/GOtIpjudUbACOndZXCN3vHsw=="],
|
||||||
@@ -1712,8 +1725,6 @@
|
|||||||
|
|
||||||
"@expo/config/@babel/code-frame": ["@babel/code-frame@7.10.4", "", { "dependencies": { "@babel/highlight": "^7.10.4" } }, "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg=="],
|
"@expo/config/@babel/code-frame": ["@babel/code-frame@7.10.4", "", { "dependencies": { "@babel/highlight": "^7.10.4" } }, "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg=="],
|
||||||
|
|
||||||
"@expo/config/getenv": ["getenv@1.0.0", "", {}, "sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg=="],
|
|
||||||
|
|
||||||
"@expo/config/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
|
"@expo/config/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
|
||||||
|
|
||||||
"@expo/config/semver": ["semver@7.7.2", "", { "bin": "bin/semver.js" }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
"@expo/config/semver": ["semver@7.7.2", "", { "bin": "bin/semver.js" }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
||||||
@@ -1726,16 +1737,12 @@
|
|||||||
|
|
||||||
"@expo/devcert/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
|
"@expo/devcert/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
|
||||||
|
|
||||||
"@expo/env/getenv": ["getenv@1.0.0", "", {}, "sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg=="],
|
|
||||||
|
|
||||||
"@expo/fingerprint/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
|
"@expo/fingerprint/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
|
||||||
|
|
||||||
"@expo/fingerprint/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
"@expo/fingerprint/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
||||||
|
|
||||||
"@expo/fingerprint/semver": ["semver@7.7.2", "", { "bin": "bin/semver.js" }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
"@expo/fingerprint/semver": ["semver@7.7.2", "", { "bin": "bin/semver.js" }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
||||||
|
|
||||||
"@expo/image-utils/getenv": ["getenv@1.0.0", "", {}, "sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg=="],
|
|
||||||
|
|
||||||
"@expo/image-utils/semver": ["semver@7.7.2", "", { "bin": "bin/semver.js" }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
"@expo/image-utils/semver": ["semver@7.7.2", "", { "bin": "bin/semver.js" }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
||||||
|
|
||||||
"@expo/json-file/@babel/code-frame": ["@babel/code-frame@7.10.4", "", { "dependencies": { "@babel/highlight": "^7.10.4" } }, "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg=="],
|
"@expo/json-file/@babel/code-frame": ["@babel/code-frame@7.10.4", "", { "dependencies": { "@babel/highlight": "^7.10.4" } }, "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg=="],
|
||||||
@@ -1770,6 +1777,8 @@
|
|||||||
|
|
||||||
"@react-navigation/bottom-tabs/@react-navigation/elements": ["@react-navigation/elements@2.5.2", "", { "dependencies": { "color": "^4.2.3", "use-latest-callback": "^0.2.4", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@react-native-masked-view/masked-view": ">= 0.2.0", "@react-navigation/native": "^7.1.14", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0" }, "optionalPeers": ["@react-native-masked-view/masked-view"] }, "sha512-aGC3ukF5+lXuiF5bK7bJyRuWCE+Tk4MZ3GoQpAb7u7+m0KmsquliDhj4UCWEUU5kUoCeoRAUvv+1lKcYKf+WTQ=="],
|
"@react-navigation/bottom-tabs/@react-navigation/elements": ["@react-navigation/elements@2.5.2", "", { "dependencies": { "color": "^4.2.3", "use-latest-callback": "^0.2.4", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@react-native-masked-view/masked-view": ">= 0.2.0", "@react-navigation/native": "^7.1.14", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0" }, "optionalPeers": ["@react-native-masked-view/masked-view"] }, "sha512-aGC3ukF5+lXuiF5bK7bJyRuWCE+Tk4MZ3GoQpAb7u7+m0KmsquliDhj4UCWEUU5kUoCeoRAUvv+1lKcYKf+WTQ=="],
|
||||||
|
|
||||||
|
"@react-navigation/drawer/@react-navigation/elements": ["@react-navigation/elements@2.5.2", "", { "dependencies": { "color": "^4.2.3", "use-latest-callback": "^0.2.4", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@react-native-masked-view/masked-view": ">= 0.2.0", "@react-navigation/native": "^7.1.14", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0" }, "optionalPeers": ["@react-native-masked-view/masked-view"] }, "sha512-aGC3ukF5+lXuiF5bK7bJyRuWCE+Tk4MZ3GoQpAb7u7+m0KmsquliDhj4UCWEUU5kUoCeoRAUvv+1lKcYKf+WTQ=="],
|
||||||
|
|
||||||
"@react-navigation/native-stack/@react-navigation/elements": ["@react-navigation/elements@2.5.2", "", { "dependencies": { "color": "^4.2.3", "use-latest-callback": "^0.2.4", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@react-native-masked-view/masked-view": ">= 0.2.0", "@react-navigation/native": "^7.1.14", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0" }, "optionalPeers": ["@react-native-masked-view/masked-view"] }, "sha512-aGC3ukF5+lXuiF5bK7bJyRuWCE+Tk4MZ3GoQpAb7u7+m0KmsquliDhj4UCWEUU5kUoCeoRAUvv+1lKcYKf+WTQ=="],
|
"@react-navigation/native-stack/@react-navigation/elements": ["@react-navigation/elements@2.5.2", "", { "dependencies": { "color": "^4.2.3", "use-latest-callback": "^0.2.4", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@react-native-masked-view/masked-view": ">= 0.2.0", "@react-navigation/native": "^7.1.14", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0" }, "optionalPeers": ["@react-native-masked-view/masked-view"] }, "sha512-aGC3ukF5+lXuiF5bK7bJyRuWCE+Tk4MZ3GoQpAb7u7+m0KmsquliDhj4UCWEUU5kUoCeoRAUvv+1lKcYKf+WTQ=="],
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
|
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
|
||||||
@@ -1820,10 +1829,6 @@
|
|||||||
|
|
||||||
"expo-modules-autolinking/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
|
"expo-modules-autolinking/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
|
||||||
|
|
||||||
"expo-router/@react-navigation/bottom-tabs": ["@react-navigation/bottom-tabs@7.3.16", "", { "dependencies": { "@react-navigation/elements": "^2.4.5", "color": "^4.2.3" }, "peerDependencies": { "@react-navigation/native": "^7.1.12", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", "react-native-screens": ">= 4.0.0" } }, "sha512-BOVtrq5J3zV3T9CeQexX20JrjECWwIgUJj0Uj0DTVuZdvPIf1AHKHDQSWcG6XqDsbqFQu9yCAfRlnt0WwdRP2w=="],
|
|
||||||
|
|
||||||
"expo-router/@react-navigation/native-stack": ["@react-navigation/native-stack@7.3.17", "", { "dependencies": { "@react-navigation/elements": "^2.4.5", "warn-once": "^0.1.1" }, "peerDependencies": { "@react-navigation/native": "^7.1.12", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", "react-native-screens": ">= 4.0.0" } }, "sha512-nPJv5E/7MYZ5NPD0sFP9DjSawEQ1fYXe0sCZT1C5EHGWK08p3+5HkVScXofDDqUtI/q6UU23uE1YoxVWgRbDRw=="],
|
|
||||||
|
|
||||||
"expo-router/semver": ["semver@7.6.3", "", { "bin": "bin/semver.js" }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
|
"expo-router/semver": ["semver@7.6.3", "", { "bin": "bin/semver.js" }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
|
||||||
|
|
||||||
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||||
|
|||||||
127
components/Alert/AlertCustom.tsx
Normal file
127
components/Alert/AlertCustom.tsx
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
import { AccentColor, MainColor } from "@/constants/color-palet";
|
||||||
|
import { TEXT_SIZE_LARGE } from "@/constants/constans-value";
|
||||||
|
import React from "react";
|
||||||
|
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
|
||||||
|
|
||||||
|
interface AlertCustomProps {
|
||||||
|
isVisible: boolean;
|
||||||
|
onLeftPress: () => void;
|
||||||
|
onRightPress: () => void;
|
||||||
|
title?: string;
|
||||||
|
message?: string;
|
||||||
|
textLeft?: string;
|
||||||
|
textRight?: string;
|
||||||
|
colorLeft?: string;
|
||||||
|
colorRight?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AlertCustom({
|
||||||
|
isVisible,
|
||||||
|
onLeftPress,
|
||||||
|
onRightPress,
|
||||||
|
title,
|
||||||
|
message,
|
||||||
|
textLeft,
|
||||||
|
textRight,
|
||||||
|
colorLeft,
|
||||||
|
colorRight,
|
||||||
|
}: AlertCustomProps) {
|
||||||
|
if (!isVisible) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.overlay}>
|
||||||
|
<View style={styles.alertBox}>
|
||||||
|
{title && message ? (
|
||||||
|
<>
|
||||||
|
<Text style={styles.alertTitle}>{title}</Text>
|
||||||
|
<Text style={styles.alertMessage}>{message}</Text>
|
||||||
|
</>
|
||||||
|
) : title ? (
|
||||||
|
<Text style={styles.alertTitle}>{title}</Text>
|
||||||
|
) : (
|
||||||
|
<Text style={styles.alertMessage}>{message}</Text>
|
||||||
|
)}
|
||||||
|
<View style={styles.alertButtons}>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={[
|
||||||
|
styles.alertButton,
|
||||||
|
colorLeft ? { backgroundColor: colorLeft } : styles.leftButton,
|
||||||
|
]}
|
||||||
|
onPress={onLeftPress}
|
||||||
|
>
|
||||||
|
<Text style={styles.buttonText}>{textLeft}</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={[
|
||||||
|
styles.alertButton,
|
||||||
|
colorRight ? { backgroundColor: colorRight } : styles.rightButton,
|
||||||
|
]}
|
||||||
|
onPress={onRightPress}
|
||||||
|
>
|
||||||
|
<Text style={styles.buttonText}>{textRight}</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
overlay: {
|
||||||
|
position: "absolute",
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
backgroundColor: "rgba(0,0,0,0.5)",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
zIndex: 999,
|
||||||
|
},
|
||||||
|
alertBox: {
|
||||||
|
width: "90%",
|
||||||
|
backgroundColor: MainColor.darkblue,
|
||||||
|
borderColor: AccentColor.blue,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderRadius: 10,
|
||||||
|
padding: 20,
|
||||||
|
alignItems: "center",
|
||||||
|
shadowColor: "#000",
|
||||||
|
shadowOffset: { width: 0, height: 2 },
|
||||||
|
shadowOpacity: 0.25,
|
||||||
|
elevation: 5,
|
||||||
|
},
|
||||||
|
alertTitle: {
|
||||||
|
fontSize: TEXT_SIZE_LARGE,
|
||||||
|
fontWeight: "bold",
|
||||||
|
marginBottom: 20,
|
||||||
|
color: MainColor.white_gray,
|
||||||
|
},
|
||||||
|
alertMessage: {
|
||||||
|
textAlign: "center",
|
||||||
|
marginBottom: 20,
|
||||||
|
color: MainColor.white_gray,
|
||||||
|
},
|
||||||
|
alertButtons: {
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
width: "100%",
|
||||||
|
},
|
||||||
|
alertButton: {
|
||||||
|
flex: 1,
|
||||||
|
padding: 10,
|
||||||
|
borderRadius: 50,
|
||||||
|
marginHorizontal: 5,
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
leftButton: {
|
||||||
|
backgroundColor: "gray",
|
||||||
|
},
|
||||||
|
rightButton: {
|
||||||
|
backgroundColor: MainColor.green,
|
||||||
|
},
|
||||||
|
buttonText: {
|
||||||
|
color: "white",
|
||||||
|
fontWeight: "bold",
|
||||||
|
},
|
||||||
|
});
|
||||||
59
components/Box/BaseBox.tsx
Normal file
59
components/Box/BaseBox.tsx
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import { AccentColor } from "@/constants/color-palet";
|
||||||
|
import { StyleProp, TouchableHighlight, View, ViewStyle } from "react-native";
|
||||||
|
|
||||||
|
interface BaseBoxProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
style?: StyleProp<ViewStyle>;
|
||||||
|
onPress?: () => void;
|
||||||
|
marginBottom?: number;
|
||||||
|
padding?: number;
|
||||||
|
paddingInline?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function BaseBox({
|
||||||
|
children,
|
||||||
|
style,
|
||||||
|
onPress,
|
||||||
|
marginBottom = 16,
|
||||||
|
padding = 12,
|
||||||
|
}: BaseBoxProps) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{onPress ? (
|
||||||
|
<TouchableHighlight
|
||||||
|
onPress={onPress}
|
||||||
|
style={[
|
||||||
|
{
|
||||||
|
backgroundColor: AccentColor.darkblue,
|
||||||
|
borderColor: AccentColor.blue,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderRadius: 10,
|
||||||
|
marginBottom,
|
||||||
|
padding,
|
||||||
|
},
|
||||||
|
style,
|
||||||
|
]}
|
||||||
|
// activeOpacity={0.7}
|
||||||
|
>
|
||||||
|
<View>{children}</View>
|
||||||
|
</TouchableHighlight>
|
||||||
|
) : (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
{
|
||||||
|
backgroundColor: AccentColor.darkblue,
|
||||||
|
borderColor: AccentColor.blue,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderRadius: 10,
|
||||||
|
marginBottom,
|
||||||
|
padding,
|
||||||
|
},
|
||||||
|
style,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
16
components/Box/BoxButtonOnFooter.tsx
Normal file
16
components/Box/BoxButtonOnFooter.tsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { GStyles } from "@/styles/global-styles";
|
||||||
|
import { StyleProp, View, ViewStyle } from "react-native";
|
||||||
|
|
||||||
|
export default function BoxButtonOnFooter({
|
||||||
|
children,
|
||||||
|
style,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
style?: StyleProp<ViewStyle>;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<View style={GStyles.bottomBar}>
|
||||||
|
<View style={[GStyles.bottomBarContainer, style]}>{children}</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
33
components/Box/InformationBox.tsx
Normal file
33
components/Box/InformationBox.tsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
|
import Grid from "../Grid/GridCustom";
|
||||||
|
import TextCustom from "../Text/TextCustom";
|
||||||
|
import BaseBox from "./BaseBox";
|
||||||
|
|
||||||
|
export default function InformationBox({ text }: { text: string }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<BaseBox>
|
||||||
|
<Grid>
|
||||||
|
<Grid.Col
|
||||||
|
span={2}
|
||||||
|
style={{ alignItems: "center", justifyContent: "center" }}
|
||||||
|
>
|
||||||
|
<Ionicons
|
||||||
|
name="information-circle-outline"
|
||||||
|
size={24}
|
||||||
|
color={MainColor.white_gray}
|
||||||
|
/>
|
||||||
|
</Grid.Col>
|
||||||
|
<Grid.Col span={10} style={{ justifyContent: "center" }}>
|
||||||
|
<TextCustom>
|
||||||
|
{text
|
||||||
|
? text
|
||||||
|
: "Lorem ipsum dolor sit amet consectetur adipisicing elit."}
|
||||||
|
</TextCustom>
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid>
|
||||||
|
</BaseBox>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
22
components/Button/BackButton.tsx
Normal file
22
components/Button/BackButton.tsx
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
|
import { Href, router } from "expo-router";
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param path - path to navigate to ?
|
||||||
|
* @default router.back()
|
||||||
|
* @returns if path : router.replace(path) else router.back()
|
||||||
|
*/
|
||||||
|
const LeftButtonCustom = ({path}: {path?: Href}) => {
|
||||||
|
return (
|
||||||
|
<Ionicons
|
||||||
|
name="arrow-back"
|
||||||
|
size={20}
|
||||||
|
color={MainColor.yellow}
|
||||||
|
onPress={() => path ? router.replace(path) : router.back()}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LeftButtonCustom;
|
||||||
29
components/Button/ButtonCenteredOnly.tsx
Normal file
29
components/Button/ButtonCenteredOnly.tsx
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||||
|
import { GStyles } from "@/styles/global-styles";
|
||||||
|
import { Feather } from "@expo/vector-icons";
|
||||||
|
import React from "react";
|
||||||
|
import ButtonCustom from "./ButtonCustom";
|
||||||
|
|
||||||
|
interface ButtonCenteredOnlyProps {
|
||||||
|
children?: React.ReactNode;
|
||||||
|
icon?: "plus" | "upload";
|
||||||
|
onPress: () => void;
|
||||||
|
}
|
||||||
|
export default function ButtonCenteredOnly({
|
||||||
|
onPress,
|
||||||
|
children,
|
||||||
|
icon = "plus"
|
||||||
|
}: ButtonCenteredOnlyProps) {
|
||||||
|
return (
|
||||||
|
<ButtonCustom
|
||||||
|
onPress={onPress}
|
||||||
|
iconLeft={
|
||||||
|
<Feather name={icon} size={ICON_SIZE_BUTTON} color={MainColor.black} />
|
||||||
|
}
|
||||||
|
style={[GStyles.buttonCentered50Percent]}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</ButtonCustom>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,57 +1,57 @@
|
|||||||
// components/Button/Button.tsx
|
// components/Button/Button.tsx
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Text, TouchableOpacity } from "react-native";
|
import { StyleProp, Text, TouchableOpacity, ViewStyle } from "react-native";
|
||||||
import buttonStyles from "./buttonStyles";
|
import { radiusMap } from "@/constants/radius-value";
|
||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { stylesButton } from "./buttonCustomStyles";
|
||||||
|
|
||||||
// Definisi props dengan TypeScript
|
// Import radiusMap
|
||||||
|
|
||||||
|
// Definisi type untuk radius
|
||||||
|
type RadiusType = keyof typeof radiusMap | number;
|
||||||
|
|
||||||
interface ButtonProps {
|
interface ButtonProps {
|
||||||
onPress: () => void;
|
children?: React.ReactNode;
|
||||||
|
onPress?: () => void;
|
||||||
title?: string;
|
title?: string;
|
||||||
backgroundColor?: string;
|
backgroundColor?: string;
|
||||||
textColor?: string;
|
textColor?: string;
|
||||||
radius?: number;
|
radius?: RadiusType; // ← bisa string enum atau number
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
iconLeft?: React.ReactNode;
|
iconLeft?: React.ReactNode;
|
||||||
|
style?: StyleProp<ViewStyle>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Props untuk ButtonCustom
|
|
||||||
* @param onPress: () => void
|
|
||||||
* @param title?: string
|
|
||||||
* @param backgroundColor?: string
|
|
||||||
* @param textColor?: string
|
|
||||||
* @param radius?: number
|
|
||||||
* @param disabled?: boolean
|
|
||||||
* @param iconLeft?: React.ReactNode
|
|
||||||
* @example iconLeft={<Icon name="arrow-right" size={20} color={MainColor.black}/>
|
|
||||||
*/
|
|
||||||
const ButtonCustom: React.FC<ButtonProps> = ({
|
const ButtonCustom: React.FC<ButtonProps> = ({
|
||||||
|
children,
|
||||||
onPress,
|
onPress,
|
||||||
title = "Button",
|
title = "Button",
|
||||||
backgroundColor = "#007AFF",
|
backgroundColor = MainColor.yellow,
|
||||||
textColor = "#FFFFFF",
|
textColor = MainColor.black,
|
||||||
radius = 8,
|
radius = 50, // default md
|
||||||
disabled = false,
|
disabled = false,
|
||||||
iconLeft,
|
iconLeft,
|
||||||
|
style,
|
||||||
}) => {
|
}) => {
|
||||||
const styles = buttonStyles({
|
|
||||||
backgroundColor,
|
|
||||||
textColor,
|
|
||||||
borderRadius: radius,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[styles.button, disabled && styles.disabled]}
|
style={[
|
||||||
|
stylesButton.button,
|
||||||
|
disabled && stylesButton.disabled,
|
||||||
|
style,
|
||||||
|
{ borderRadius: radius },
|
||||||
|
{ backgroundColor },
|
||||||
|
]}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
activeOpacity={0.8}
|
activeOpacity={0.8}
|
||||||
>
|
>
|
||||||
{/* Render icon jika tersedia */}
|
{/* Render icon jika tersedia */}
|
||||||
{iconLeft && iconLeft}
|
{iconLeft && iconLeft}
|
||||||
<Text style={styles.buttonText}>{title}</Text>
|
<Text style={[stylesButton.buttonText, { color: textColor }]}>
|
||||||
|
{children || title}
|
||||||
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,31 +1,25 @@
|
|||||||
// components/Button/buttonStyles.js
|
// components/Button/buttonStyles.js
|
||||||
|
|
||||||
import { MainColor } from "@/constants/color-palet";
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { TEXT_SIZE_MEDIUM } from "@/constants/constans-value";
|
||||||
import { StyleSheet } from "react-native";
|
import { StyleSheet } from "react-native";
|
||||||
|
|
||||||
export default function buttonStyles({
|
export const stylesButton = StyleSheet.create({
|
||||||
backgroundColor = "#007AFF",
|
|
||||||
textColor = "#FFFFFF",
|
|
||||||
borderRadius = 8,
|
|
||||||
}) {
|
|
||||||
return StyleSheet.create({
|
|
||||||
button: {
|
button: {
|
||||||
backgroundColor,
|
backgroundColor: MainColor.yellow,
|
||||||
paddingVertical: 12,
|
paddingVertical: 12,
|
||||||
paddingHorizontal: 20,
|
paddingHorizontal: 20,
|
||||||
borderRadius,
|
|
||||||
flexDirection: "row", // 👈 Tambahkan baris ini
|
flexDirection: "row", // 👈 Tambahkan baris ini
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
gap: 8,
|
gap: 8,
|
||||||
},
|
},
|
||||||
buttonText: {
|
buttonText: {
|
||||||
color: textColor,
|
color: MainColor.black,
|
||||||
fontSize: 16,
|
fontSize: TEXT_SIZE_MEDIUM,
|
||||||
fontWeight: "600",
|
fontWeight: "600",
|
||||||
},
|
},
|
||||||
disabled: {
|
disabled: {
|
||||||
backgroundColor: MainColor.disabled,
|
backgroundColor: MainColor.disabled,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
|
||||||
0
components/Camera/CameraCustom.tsx
Normal file
0
components/Camera/CameraCustom.tsx
Normal file
183
components/Drawer/DrawerCustom.tsx
Normal file
183
components/Drawer/DrawerCustom.tsx
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
import React, { useEffect, useRef } from "react";
|
||||||
|
import {
|
||||||
|
Animated,
|
||||||
|
PanResponder,
|
||||||
|
StyleSheet,
|
||||||
|
View,
|
||||||
|
InteractionManager,
|
||||||
|
} from "react-native";
|
||||||
|
|
||||||
|
import { AccentColor, MainColor } from "@/constants/color-palet";
|
||||||
|
import { DRAWER_HEIGHT } from "@/constants/constans-value";
|
||||||
|
|
||||||
|
interface DrawerCustomProps {
|
||||||
|
children?: React.ReactNode;
|
||||||
|
height?: number;
|
||||||
|
isVisible: boolean;
|
||||||
|
drawerAnim?: Animated.Value;
|
||||||
|
closeDrawer: () => void;
|
||||||
|
// openLogoutAlert: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param drawerAnim
|
||||||
|
* @example const drawerAnim = useRef(new Animated.Value(DRAWER_HEIGHT)).current; // mulai di luar bawah layar
|
||||||
|
*/
|
||||||
|
export default function DrawerCustom({
|
||||||
|
children,
|
||||||
|
height,
|
||||||
|
isVisible,
|
||||||
|
drawerAnim,
|
||||||
|
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) => {
|
||||||
|
return gestureState.dy > 10; // gesek ke bawah
|
||||||
|
},
|
||||||
|
onPanResponderMove: (_, gestureState) => {
|
||||||
|
const offset = gestureState.dy;
|
||||||
|
if (offset >= 0 && offset <= DRAWER_HEIGHT) {
|
||||||
|
drawerAnima.setValue(offset);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onPanResponderRelease: (_, gestureState) => {
|
||||||
|
if (gestureState.dy > 200) {
|
||||||
|
InteractionManager.runAfterInteractions(() => {
|
||||||
|
closeDrawer();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Animated.spring(drawerAnima, {
|
||||||
|
toValue: 0,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
).current;
|
||||||
|
|
||||||
|
if (!isVisible) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Overlay Gelap */}
|
||||||
|
<View
|
||||||
|
style={styles.overlay}
|
||||||
|
pointerEvents="auto"
|
||||||
|
onTouchStart={() => {
|
||||||
|
InteractionManager.runAfterInteractions(() => {
|
||||||
|
closeDrawer();
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Custom Bottom Drawer */}
|
||||||
|
<Animated.View
|
||||||
|
style={[
|
||||||
|
styles.drawer,
|
||||||
|
{
|
||||||
|
height: height || DRAWER_HEIGHT,
|
||||||
|
transform: [{ translateY: drawerAnima }],
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
{...panResponder.panHandlers}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={[styles.headerBar, { backgroundColor: MainColor.white }]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{children}
|
||||||
|
|
||||||
|
{/* <TouchableOpacity
|
||||||
|
style={styles.menuItem}
|
||||||
|
onPress={() => {
|
||||||
|
alert("Pilihan 1 diklik");
|
||||||
|
closeDrawer();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text>Menu Item 1</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
<TouchableOpacity
|
||||||
|
style={styles.menuItem}
|
||||||
|
onPress={() => {
|
||||||
|
alert("Pilihan 2 diklik");
|
||||||
|
closeDrawer();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text>Menu Item 2</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
|
||||||
|
<TouchableOpacity
|
||||||
|
style={styles.menuItem}
|
||||||
|
onPress={() => alert("Logout via Alert bawaan")}
|
||||||
|
>
|
||||||
|
<Text style={{ color: "red" }}>Keluar</Text>
|
||||||
|
</TouchableOpacity> */}
|
||||||
|
</Animated.View>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
overlay: {
|
||||||
|
position: "absolute",
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
backgroundColor: "black",
|
||||||
|
opacity: 0.6,
|
||||||
|
zIndex: 998,
|
||||||
|
},
|
||||||
|
drawer: {
|
||||||
|
position: "absolute",
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
backgroundColor: AccentColor.darkblue,
|
||||||
|
borderTopLeftRadius: 20,
|
||||||
|
borderTopRightRadius: 20,
|
||||||
|
padding: 20,
|
||||||
|
shadowColor: "#000",
|
||||||
|
shadowOffset: { width: 0, height: -2 },
|
||||||
|
shadowOpacity: 0.2,
|
||||||
|
elevation: 5,
|
||||||
|
zIndex: 999,
|
||||||
|
},
|
||||||
|
headerBar: {
|
||||||
|
width: 40,
|
||||||
|
height: 5,
|
||||||
|
backgroundColor: MainColor.white,
|
||||||
|
borderRadius: 5,
|
||||||
|
alignSelf: "center",
|
||||||
|
marginVertical: 10,
|
||||||
|
},
|
||||||
|
menuItem: {
|
||||||
|
padding: 15,
|
||||||
|
},
|
||||||
|
});
|
||||||
57
components/Drawer/MenuDrawerDynamicGird.tsx
Normal file
57
components/Drawer/MenuDrawerDynamicGird.tsx
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import { AccentColor, MainColor } from "@/constants/color-palet";
|
||||||
|
import { ICON_SIZE_MEDIUM, TEXT_SIZE_SMALL } from "@/constants/constans-value";
|
||||||
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
|
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
|
||||||
|
|
||||||
|
const MenuDrawerDynamicGrid = ({ data, columns = 3, onPressItem }: any) => {
|
||||||
|
const numColumns = columns;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
{data.map((item: any, index: any) => (
|
||||||
|
<TouchableOpacity
|
||||||
|
key={index}
|
||||||
|
style={[styles.itemContainer, { flexBasis: `${100 / numColumns}%` }]}
|
||||||
|
onPress={() => onPressItem?.(item)}
|
||||||
|
>
|
||||||
|
<View style={styles.iconContainer}>
|
||||||
|
<Ionicons
|
||||||
|
name={item.icon}
|
||||||
|
size={ICON_SIZE_MEDIUM}
|
||||||
|
color={item.color || MainColor.white_gray}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<Text style={styles.label}>{item.label}</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MenuDrawerDynamicGrid;
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flexDirection: "row",
|
||||||
|
flexWrap: "wrap",
|
||||||
|
padding: 0,
|
||||||
|
},
|
||||||
|
itemContainer: {
|
||||||
|
padding: 10,
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
iconContainer: {
|
||||||
|
width: 56,
|
||||||
|
height: 56,
|
||||||
|
borderRadius: 28,
|
||||||
|
backgroundColor: AccentColor.blue,
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
marginTop: 10,
|
||||||
|
fontSize: TEXT_SIZE_SMALL,
|
||||||
|
textAlign: "center",
|
||||||
|
color: MainColor.white_gray,
|
||||||
|
},
|
||||||
|
});
|
||||||
114
components/Grid/GridCustom.tsx
Normal file
114
components/Grid/GridCustom.tsx
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
import React, { createContext, useContext, useMemo } from "react";
|
||||||
|
import { StyleSheet, useWindowDimensions, View, ViewStyle } from "react-native";
|
||||||
|
|
||||||
|
// Tipe untuk span
|
||||||
|
type SpanValue = {
|
||||||
|
base?: number;
|
||||||
|
md?: number;
|
||||||
|
lg?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Props untuk Grid.Col
|
||||||
|
interface ColProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
span?: number | SpanValue;
|
||||||
|
style?: ViewStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Props untuk Grid
|
||||||
|
interface GridProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
gap?: number;
|
||||||
|
columns?: number;
|
||||||
|
containerStyle?: ViewStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context untuk menyimpan konfigurasi grid
|
||||||
|
type GridContextType = {
|
||||||
|
gap: number;
|
||||||
|
columns: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const GridContext = createContext<GridContextType>({
|
||||||
|
gap: 0,
|
||||||
|
columns: 12,
|
||||||
|
});
|
||||||
|
|
||||||
|
const useGrid = () => useContext(GridContext);
|
||||||
|
|
||||||
|
// Helper untuk menentukan span berdasarkan lebar layar
|
||||||
|
const getSpan = (
|
||||||
|
spanProp: number | SpanValue | undefined,
|
||||||
|
width: number
|
||||||
|
): number => {
|
||||||
|
if (typeof spanProp === "number") return spanProp;
|
||||||
|
|
||||||
|
const span = spanProp || { base: 12 };
|
||||||
|
|
||||||
|
if (width >= 992 && span.lg) return span.lg;
|
||||||
|
if (width >= 768 && span.md) return span.md;
|
||||||
|
return span.base ?? 12;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Grid Component
|
||||||
|
const GridComponent: React.FC<GridProps> = ({
|
||||||
|
children,
|
||||||
|
gap = 6,
|
||||||
|
columns = 12,
|
||||||
|
containerStyle,
|
||||||
|
}) => {
|
||||||
|
const contextValue = useMemo(() => ({ gap, columns }), [gap, columns]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<GridContext.Provider value={contextValue}>
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.container,
|
||||||
|
{ marginHorizontal: -gap / 2 },
|
||||||
|
containerStyle,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{React.Children.map(children, (child) =>
|
||||||
|
React.isValidElement(child)
|
||||||
|
? React.cloneElement(child as React.ReactElement<ColProps>, {})
|
||||||
|
: child
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</GridContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Grid.Col Component
|
||||||
|
const Col: React.FC<ColProps> = ({ children, span, style }) => {
|
||||||
|
const { gap, columns } = useGrid();
|
||||||
|
const { width } = useWindowDimensions();
|
||||||
|
|
||||||
|
const colSpan = getSpan(span, width);
|
||||||
|
const margin = gap / 2;
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
col: {
|
||||||
|
flexBasis: `${(100 / columns) * colSpan}%`,
|
||||||
|
paddingVertical: margin,
|
||||||
|
// marginBottom: gap,
|
||||||
|
marginBlock: gap,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return <View style={[styles.col, style]}>{children}</View>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Export bersama-sama
|
||||||
|
const Grid = Object.assign(GridComponent, { Col });
|
||||||
|
|
||||||
|
export default Grid;
|
||||||
|
|
||||||
|
// Styles
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flexDirection: "row",
|
||||||
|
flexWrap: "wrap",
|
||||||
|
justifyContent: "flex-start",
|
||||||
|
marginInline: 0.1
|
||||||
|
},
|
||||||
|
});
|
||||||
57
components/Image/AvatarCustom.tsx
Normal file
57
components/Image/AvatarCustom.tsx
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import DUMMY_IMAGE from "@/constants/dummy-image-value";
|
||||||
|
import { Image, ImageSourcePropType, StyleSheet } from "react-native";
|
||||||
|
|
||||||
|
type Size = "base" | "sm" | "md" | "lg" | "xl";
|
||||||
|
|
||||||
|
interface AvatarCustomProps {
|
||||||
|
source?: ImageSourcePropType;
|
||||||
|
size?: Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sizeMap = {
|
||||||
|
base: 40,
|
||||||
|
sm: 60,
|
||||||
|
md: 80,
|
||||||
|
lg: 100,
|
||||||
|
xl: 120,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function AvatarCustom({
|
||||||
|
source = DUMMY_IMAGE.avatar,
|
||||||
|
size = "base",
|
||||||
|
}: AvatarCustomProps) {
|
||||||
|
const dimension = sizeMap[size];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Image
|
||||||
|
source={source}
|
||||||
|
style={[
|
||||||
|
styles.overlappingAvatar,
|
||||||
|
{
|
||||||
|
width: dimension,
|
||||||
|
height: dimension,
|
||||||
|
borderRadius: dimension / 2,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
resizeMode="cover"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
},
|
||||||
|
overlappingAvatar: {
|
||||||
|
borderWidth: 2,
|
||||||
|
borderColor: "#fff",
|
||||||
|
backgroundColor: MainColor.white_gray,
|
||||||
|
// shadowColor: "#000",
|
||||||
|
// shadowOffset: { width: 0, height: 2 },
|
||||||
|
// shadowOpacity: 0.2,
|
||||||
|
shadowRadius: 3,
|
||||||
|
elevation: 3,
|
||||||
|
},
|
||||||
|
});
|
||||||
20
components/Image/LandscapeFrameUploaded.tsx
Normal file
20
components/Image/LandscapeFrameUploaded.tsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import DUMMY_IMAGE from "@/constants/dummy-image-value";
|
||||||
|
import { Image } from "react-native";
|
||||||
|
import BaseBox from "../Box/BaseBox";
|
||||||
|
|
||||||
|
export default function LandscapeFrameUploaded() {
|
||||||
|
return (
|
||||||
|
<BaseBox
|
||||||
|
style={{
|
||||||
|
height: 250,
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
source={DUMMY_IMAGE.background}
|
||||||
|
resizeMode="cover"
|
||||||
|
style={{ width: "100%", height: "100%", borderRadius: 10 }}
|
||||||
|
/>
|
||||||
|
</BaseBox>
|
||||||
|
);
|
||||||
|
}
|
||||||
111
components/Select/SelectCustom.tsx
Normal file
111
components/Select/SelectCustom.tsx
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
// components/Select.tsx
|
||||||
|
import { GStyles } from "@/styles/global-styles";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import {
|
||||||
|
FlatList,
|
||||||
|
Modal,
|
||||||
|
Pressable,
|
||||||
|
Text,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
|
} from "react-native";
|
||||||
|
|
||||||
|
type SelectItem = {
|
||||||
|
label: string;
|
||||||
|
value: string | number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SelectProps = {
|
||||||
|
label?: string;
|
||||||
|
placeholder?: string;
|
||||||
|
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> = ({
|
||||||
|
label,
|
||||||
|
placeholder = "Pilih opsi",
|
||||||
|
data,
|
||||||
|
value,
|
||||||
|
required = false, // <-- default false
|
||||||
|
disabled = false, // <-- default false
|
||||||
|
onChange,
|
||||||
|
borderRadius = 8,
|
||||||
|
}) => {
|
||||||
|
const [modalVisible, setModalVisible] = useState(false);
|
||||||
|
|
||||||
|
const selectedItem = data.find((item) => item.value === value);
|
||||||
|
|
||||||
|
const hasError = required && value === null; // <-- check if empty and required
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={GStyles.inputContainerArea}>
|
||||||
|
{label && (
|
||||||
|
<Text style={GStyles.inputLabel}>
|
||||||
|
{label}
|
||||||
|
{required && <Text style={GStyles.inputRequired}> *</Text>}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
<Pressable
|
||||||
|
style={[
|
||||||
|
{ borderRadius },
|
||||||
|
hasError ? GStyles.inputErrorBorder : null,
|
||||||
|
GStyles.inputContainerInput,
|
||||||
|
disabled && GStyles.disabledBox,
|
||||||
|
]} // <-- add error style
|
||||||
|
onPress={() => !disabled && setModalVisible(true)}
|
||||||
|
>
|
||||||
|
<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={GStyles.selectModalOverlay}
|
||||||
|
activeOpacity={1}
|
||||||
|
onPressOut={() => setModalVisible(false)}
|
||||||
|
>
|
||||||
|
<View style={GStyles.selectModalContent}>
|
||||||
|
<FlatList
|
||||||
|
data={data}
|
||||||
|
keyExtractor={(item) => String(item.value)}
|
||||||
|
renderItem={({ item }) => (
|
||||||
|
<TouchableOpacity
|
||||||
|
style={GStyles.selectOption}
|
||||||
|
onPress={() => {
|
||||||
|
onChange(item.value);
|
||||||
|
setModalVisible(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text>{item.label}</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
{/* Optional Error Message */}
|
||||||
|
{hasError && (
|
||||||
|
<Text style={GStyles.inputErrorMessage}>Harap pilih salah satu</Text>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SelectCustom;
|
||||||
67
components/Stack/StackCustom.tsx
Normal file
67
components/Stack/StackCustom.tsx
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
|
// components/Stack.tsx
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { View, ViewStyle, StyleSheet } from "react-native";
|
||||||
|
|
||||||
|
import { AlignType, GapSizeType, JustifyType } from "@/components/Stack/stack-types";
|
||||||
|
|
||||||
|
interface StackProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
align?: AlignType;
|
||||||
|
justify?: JustifyType;
|
||||||
|
gap?: GapSizeType;
|
||||||
|
direction?: "row" | "column";
|
||||||
|
style?: ViewStyle | ViewStyle[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const StackCustom: React.FC<StackProps> = ({
|
||||||
|
children,
|
||||||
|
align = "stretch",
|
||||||
|
justify = "flex-start",
|
||||||
|
gap = "md",
|
||||||
|
direction = "column",
|
||||||
|
style,
|
||||||
|
}) => {
|
||||||
|
const spacing = convertToSpacing(gap);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
// styles.stack,
|
||||||
|
{
|
||||||
|
flexDirection: direction,
|
||||||
|
alignItems: align,
|
||||||
|
justifyContent: justify,
|
||||||
|
gap: spacing,
|
||||||
|
},
|
||||||
|
style,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fungsi untuk mengubah nilai gap ke dalam ukuran pixel
|
||||||
|
const convertToSpacing = (value: GapSizeType): number => {
|
||||||
|
if (typeof value === "number") return value;
|
||||||
|
|
||||||
|
const sizes: Record<string, number> = {
|
||||||
|
xs: 4,
|
||||||
|
sm: 8,
|
||||||
|
md: 16,
|
||||||
|
lg: 24,
|
||||||
|
xl: 32,
|
||||||
|
};
|
||||||
|
|
||||||
|
return sizes[value] || 16; // default md
|
||||||
|
};
|
||||||
|
|
||||||
|
// const styles = StyleSheet.create({
|
||||||
|
// stack: {
|
||||||
|
// flex: 1,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
|
export default StackCustom;
|
||||||
19
components/Stack/stack-types.ts
Normal file
19
components/Stack/stack-types.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
// types/stack.types.ts
|
||||||
|
|
||||||
|
export type AlignType =
|
||||||
|
| "stretch"
|
||||||
|
| "flex-start"
|
||||||
|
| "center"
|
||||||
|
| "flex-end"
|
||||||
|
| "baseline";
|
||||||
|
|
||||||
|
export type JustifyType =
|
||||||
|
| "flex-start"
|
||||||
|
| "center"
|
||||||
|
| "flex-end"
|
||||||
|
| "space-between"
|
||||||
|
| "space-around"
|
||||||
|
| "space-evenly";
|
||||||
|
|
||||||
|
export type GapSizeType = "xs" | "sm" | "md" | "lg" | "xl" | number;
|
||||||
|
// | string;
|
||||||
120
components/Text/TextCustom.tsx
Normal file
120
components/Text/TextCustom.tsx
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import {
|
||||||
|
TEXT_SIZE_LARGE,
|
||||||
|
TEXT_SIZE_MEDIUM,
|
||||||
|
TEXT_SIZE_SMALL,
|
||||||
|
} from "@/constants/constans-value";
|
||||||
|
import React from "react";
|
||||||
|
import { Text as RNText, StyleProp, StyleSheet, TextStyle, TouchableOpacity } from "react-native";
|
||||||
|
|
||||||
|
// Tambahkan type TextAlignProps agar lebih type-safe
|
||||||
|
type TextAlign = "left" | "center" | "right";
|
||||||
|
|
||||||
|
interface TextCustomProps {
|
||||||
|
children: string | React.ReactNode;
|
||||||
|
style?: StyleProp<TextStyle>;
|
||||||
|
bold?: boolean;
|
||||||
|
semiBold?: boolean;
|
||||||
|
size?: "default" | "large" | "small";
|
||||||
|
color?: "default" | "yellow" | "red";
|
||||||
|
align?: TextAlign; // Prop untuk alignment
|
||||||
|
truncate?: boolean | number;
|
||||||
|
onPress?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TextCustom: React.FC<TextCustomProps> = ({
|
||||||
|
children,
|
||||||
|
style,
|
||||||
|
bold = false,
|
||||||
|
semiBold = false,
|
||||||
|
size = "default",
|
||||||
|
color = "default",
|
||||||
|
align = "left", // Default alignment
|
||||||
|
truncate = false,
|
||||||
|
onPress,
|
||||||
|
}) => {
|
||||||
|
const getStyle = () => {
|
||||||
|
let selectedStyles = [];
|
||||||
|
|
||||||
|
// Base style
|
||||||
|
selectedStyles.push(styles.default);
|
||||||
|
|
||||||
|
// Font weight
|
||||||
|
if (bold) selectedStyles.push(styles.bold);
|
||||||
|
else if (semiBold) selectedStyles.push(styles.semiBold);
|
||||||
|
|
||||||
|
// Size
|
||||||
|
if (size === "large") selectedStyles.push(styles.large);
|
||||||
|
else if (size === "small") selectedStyles.push(styles.small);
|
||||||
|
|
||||||
|
// Color
|
||||||
|
if (color === "yellow") selectedStyles.push(styles.yellow);
|
||||||
|
else if (color === "red") selectedStyles.push(styles.red);
|
||||||
|
|
||||||
|
// Alignment
|
||||||
|
if (align) {
|
||||||
|
selectedStyles.push({ textAlign: align });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override with passed style
|
||||||
|
if (style) selectedStyles.push(style);
|
||||||
|
|
||||||
|
return selectedStyles;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
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>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TextCustom;
|
||||||
|
|
||||||
|
export const styles = StyleSheet.create({
|
||||||
|
default: {
|
||||||
|
fontSize: TEXT_SIZE_MEDIUM,
|
||||||
|
color: MainColor.white,
|
||||||
|
fontFamily: "Poppins-Regular",
|
||||||
|
},
|
||||||
|
bold: {
|
||||||
|
fontFamily: "Poppins-Bold",
|
||||||
|
fontWeight: "700",
|
||||||
|
},
|
||||||
|
semiBold: {
|
||||||
|
fontFamily: "Poppins-SemiBold",
|
||||||
|
fontWeight: "500",
|
||||||
|
},
|
||||||
|
large: {
|
||||||
|
fontSize: TEXT_SIZE_LARGE,
|
||||||
|
},
|
||||||
|
small: {
|
||||||
|
fontSize: TEXT_SIZE_SMALL,
|
||||||
|
},
|
||||||
|
yellow: {
|
||||||
|
color: MainColor.yellow,
|
||||||
|
},
|
||||||
|
red: {
|
||||||
|
color: MainColor.red,
|
||||||
|
},
|
||||||
|
});
|
||||||
143
components/TextArea/TextAreaCustom.tsx
Normal file
143
components/TextArea/TextAreaCustom.tsx
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
import { GStyles } from "@/styles/global-styles";
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import {
|
||||||
|
TextInput as RNTextInput,
|
||||||
|
StyleProp,
|
||||||
|
Text,
|
||||||
|
View,
|
||||||
|
ViewStyle,
|
||||||
|
} from "react-native";
|
||||||
|
|
||||||
|
type IconType = React.ReactNode | string;
|
||||||
|
|
||||||
|
type BaseProps = {
|
||||||
|
iconLeft?: IconType;
|
||||||
|
iconRight?: IconType;
|
||||||
|
label?: string;
|
||||||
|
required?: boolean;
|
||||||
|
error?: string;
|
||||||
|
fontColor?: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
borderRadius?: number;
|
||||||
|
autosize?: boolean;
|
||||||
|
minRows?: number;
|
||||||
|
maxRows?: number;
|
||||||
|
showCount?: boolean;
|
||||||
|
maxLength?: number;
|
||||||
|
style?: StyleProp<ViewStyle>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type NativeTextInputProps = Omit<
|
||||||
|
React.ComponentProps<typeof RNTextInput>,
|
||||||
|
"style"
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type TextAreaCustomProps = BaseProps & NativeTextInputProps;
|
||||||
|
|
||||||
|
const TextAreaCustom: React.FC<TextAreaCustomProps> = ({
|
||||||
|
iconLeft,
|
||||||
|
iconRight,
|
||||||
|
label,
|
||||||
|
required = false,
|
||||||
|
error = "",
|
||||||
|
fontColor = "#000",
|
||||||
|
disabled = false,
|
||||||
|
borderRadius = 8,
|
||||||
|
autosize = false,
|
||||||
|
minRows = 3,
|
||||||
|
maxRows = 6,
|
||||||
|
showCount = false,
|
||||||
|
maxLength,
|
||||||
|
value,
|
||||||
|
onChangeText,
|
||||||
|
style,
|
||||||
|
...rest
|
||||||
|
}) => {
|
||||||
|
const [numberOfLines, setNumberOfLines] = useState(minRows);
|
||||||
|
|
||||||
|
// Autosizing logic
|
||||||
|
useEffect(() => {
|
||||||
|
if (!autosize || !value) return;
|
||||||
|
|
||||||
|
const text = value as string;
|
||||||
|
const lines = text.split("\n").length;
|
||||||
|
const newLines = Math.max(minRows, Math.min(maxRows, lines));
|
||||||
|
setNumberOfLines(newLines);
|
||||||
|
}, [value, autosize, minRows, maxRows]);
|
||||||
|
|
||||||
|
const hasError = Boolean(error);
|
||||||
|
|
||||||
|
const renderIcon = (icon: IconType) => {
|
||||||
|
if (!icon) return null;
|
||||||
|
return typeof icon === "string" ? (
|
||||||
|
<Text style={GStyles.inputIconText}>{icon}</Text>
|
||||||
|
) : (
|
||||||
|
icon
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={GStyles.inputContainerArea}>
|
||||||
|
{label && (
|
||||||
|
<Text style={GStyles.inputLabel}>
|
||||||
|
{label}
|
||||||
|
{required && <Text style={GStyles.inputRequired}> *</Text>}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
GStyles.inputContainerInput,
|
||||||
|
disabled && GStyles.disabledBox,
|
||||||
|
hasError ? GStyles.inputErrorBorder : {},
|
||||||
|
{ borderRadius },
|
||||||
|
style,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{iconLeft && (
|
||||||
|
<View style={GStyles.inputIcon}>{renderIcon(iconLeft)}</View>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<RNTextInput
|
||||||
|
maxLength={maxLength}
|
||||||
|
multiline
|
||||||
|
numberOfLines={numberOfLines}
|
||||||
|
style={[
|
||||||
|
GStyles.inputText,
|
||||||
|
GStyles.textAreaInput,
|
||||||
|
{ color: fontColor },
|
||||||
|
]}
|
||||||
|
editable={!disabled}
|
||||||
|
value={value as string}
|
||||||
|
onChangeText={onChangeText}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{iconRight && (
|
||||||
|
<View style={GStyles.inputIcon}>{renderIcon(iconRight)}</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Error Message atau Counter */}
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
marginTop: 4,
|
||||||
|
minHeight: 16,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{hasError ? (
|
||||||
|
<Text style={GStyles.inputErrorMessage}>{error}</Text>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{showCount && maxLength ? (
|
||||||
|
<Text style={GStyles.inputMaxLength}>
|
||||||
|
{(value as string)?.length || 0}/{maxLength}
|
||||||
|
</Text>
|
||||||
|
) : null}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TextAreaCustom;
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
// components/TextInputCustom.tsx
|
import { GStyles } from "@/styles/global-styles";
|
||||||
|
|
||||||
import Ionicons from "@expo/vector-icons/Ionicons";
|
import Ionicons from "@expo/vector-icons/Ionicons";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import {
|
import {
|
||||||
@@ -10,7 +9,6 @@ import {
|
|||||||
View,
|
View,
|
||||||
ViewStyle,
|
ViewStyle,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
import { textInputStyles } from "./textInputStyles";
|
|
||||||
|
|
||||||
type IconType = React.ReactNode | string;
|
type IconType = React.ReactNode | string;
|
||||||
|
|
||||||
@@ -25,63 +23,92 @@ type Props = {
|
|||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
borderRadius?: number;
|
borderRadius?: number;
|
||||||
style?: StyleProp<ViewStyle>;
|
style?: StyleProp<ViewStyle>;
|
||||||
|
maxLength?: number;
|
||||||
} & Omit<React.ComponentProps<typeof RNTextInput>, "style">;
|
} & Omit<React.ComponentProps<typeof RNTextInput>, "style">;
|
||||||
|
|
||||||
export const TextInputCustom = ({
|
const TextInputCustom = ({
|
||||||
iconLeft,
|
iconLeft,
|
||||||
iconRight,
|
iconRight,
|
||||||
label,
|
label,
|
||||||
required = false,
|
required = false,
|
||||||
error = "",
|
error: externalError = "",
|
||||||
secureTextEntry = false,
|
secureTextEntry = false,
|
||||||
fontColor = "#000",
|
fontColor = "#000",
|
||||||
disabled = false,
|
disabled = false,
|
||||||
borderRadius = 8,
|
borderRadius = 8,
|
||||||
style,
|
style,
|
||||||
|
keyboardType,
|
||||||
|
onChangeText,
|
||||||
|
maxLength,
|
||||||
...rest
|
...rest
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const [isPasswordVisible, setIsPasswordVisible] = useState(false);
|
const [isPasswordVisible, setIsPasswordVisible] = useState(false);
|
||||||
|
const [internalError, setInternalError] = useState("");
|
||||||
|
|
||||||
// Helper untuk render ikon
|
// Helper untuk render ikon
|
||||||
const renderIcon = (icon: IconType) => {
|
const renderIcon = (icon: IconType) => {
|
||||||
if (!icon) return null;
|
if (!icon) return null;
|
||||||
return typeof icon === "string" ? (
|
return typeof icon === "string" ? (
|
||||||
<Text style={textInputStyles.iconText}>{icon}</Text>
|
<Text style={GStyles.inputIconText}>{icon}</Text>
|
||||||
) : (
|
) : (
|
||||||
icon
|
icon
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Validasi email jika keyboardType = email-address
|
||||||
|
const handleTextChange = (text: string) => {
|
||||||
|
if (keyboardType === "email-address") {
|
||||||
|
const isValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(text);
|
||||||
|
if (!isValid) {
|
||||||
|
setInternalError("Masukkan email yang valid");
|
||||||
|
} else {
|
||||||
|
setInternalError("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panggil onChangeText eksternal jika ada
|
||||||
|
if (onChangeText) {
|
||||||
|
onChangeText(text);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={textInputStyles.container}>
|
<View style={GStyles.inputContainerArea}>
|
||||||
{label && (
|
{label && (
|
||||||
<Text style={textInputStyles.label}>
|
<Text style={GStyles.inputLabel}>
|
||||||
{label}
|
{label}
|
||||||
{required && <Text style={textInputStyles.required}> *</Text>}
|
{required && <Text style={GStyles.inputRequired}> *</Text>}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
textInputStyles.inputContainer,
|
|
||||||
disabled && textInputStyles.disabled,
|
|
||||||
{ borderRadius },
|
|
||||||
error ? textInputStyles.errorBorder : null,
|
|
||||||
style,
|
style,
|
||||||
|
{ borderRadius },
|
||||||
|
externalError || internalError ? GStyles.inputErrorBorder : null,
|
||||||
|
GStyles.inputContainerInput,
|
||||||
|
disabled && GStyles.disabledBox,
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{iconLeft && (
|
{/* {iconLeft && (
|
||||||
<View style={textInputStyles.icon}>{renderIcon(iconLeft)}</View>
|
<View style={GStyles.inputIcon}>{renderIcon(iconLeft)}</View>
|
||||||
)}
|
)} */}
|
||||||
<RNTextInput
|
<RNTextInput
|
||||||
style={[textInputStyles.input, { color: fontColor }]}
|
style={[
|
||||||
|
GStyles.inputText,
|
||||||
|
{ color: fontColor },
|
||||||
|
disabled && GStyles.inputPlaceholderDisabled, // <-- placeholder saat disabled
|
||||||
|
]}
|
||||||
editable={!disabled}
|
editable={!disabled}
|
||||||
secureTextEntry={secureTextEntry && !isPasswordVisible}
|
secureTextEntry={secureTextEntry && !isPasswordVisible}
|
||||||
|
keyboardType={keyboardType}
|
||||||
|
onChangeText={handleTextChange}
|
||||||
|
maxLength={maxLength}
|
||||||
{...rest}
|
{...rest}
|
||||||
/>
|
/>
|
||||||
{secureTextEntry && (
|
{secureTextEntry && (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
onPress={() => setIsPasswordVisible((prev) => !prev)}
|
onPress={() => setIsPasswordVisible((prev) => !prev)}
|
||||||
style={textInputStyles.icon}
|
style={GStyles.inputIcon}
|
||||||
>
|
>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name={isPasswordVisible ? "eye-off" : "eye"}
|
name={isPasswordVisible ? "eye-off" : "eye"}
|
||||||
@@ -91,10 +118,17 @@ export const TextInputCustom = ({
|
|||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
)}
|
)}
|
||||||
{iconRight && (
|
{iconRight && (
|
||||||
<View style={textInputStyles.icon}>{renderIcon(iconRight)}</View>
|
<View style={GStyles.inputIcon}>{renderIcon(iconRight)}</View>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
{error ? <Text style={textInputStyles.errorMessage}>{error}</Text> : null}
|
{/* Prioritaskan error eksternal */}
|
||||||
|
{externalError || internalError ? (
|
||||||
|
<Text style={GStyles.inputErrorMessage}>
|
||||||
|
{externalError || internalError}
|
||||||
|
</Text>
|
||||||
|
) : null}
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default TextInputCustom;
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
// components/text-input.styles.ts
|
|
||||||
import { AccentColor, MainColor } from "@/constants/color-palet";
|
|
||||||
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,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Tanda bintang merah untuk required
|
|
||||||
required: {
|
|
||||||
color: "red",
|
|
||||||
},
|
|
||||||
|
|
||||||
// Pesan error di bawah input
|
|
||||||
errorMessage: {
|
|
||||||
marginTop: 4,
|
|
||||||
fontSize: 12,
|
|
||||||
color: MainColor.red,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Wrapper input (View pembungkus TextInput)
|
|
||||||
inputContainer: {
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center",
|
|
||||||
borderWidth: 1,
|
|
||||||
borderColor: AccentColor.white,
|
|
||||||
backgroundColor: MainColor.login,
|
|
||||||
paddingHorizontal: 12,
|
|
||||||
height: 50,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Style saat disabled
|
|
||||||
disabled: {
|
|
||||||
backgroundColor: "#f9f9f9",
|
|
||||||
borderColor: "#e0e0e0",
|
|
||||||
},
|
|
||||||
|
|
||||||
// Input utama (TextInput)
|
|
||||||
input: {
|
|
||||||
flex: 1,
|
|
||||||
fontSize: 16,
|
|
||||||
paddingVertical: 0,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Ikon di kiri/kanan
|
|
||||||
icon: {
|
|
||||||
marginHorizontal: 4,
|
|
||||||
justifyContent: "center",
|
|
||||||
},
|
|
||||||
|
|
||||||
// Teks ikon jika berupa string
|
|
||||||
iconText: {
|
|
||||||
fontSize: 16,
|
|
||||||
color: "#000",
|
|
||||||
},
|
|
||||||
|
|
||||||
// Border merah jika ada error
|
|
||||||
errorBorder: {
|
|
||||||
borderColor: "red",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
27
components/_Interface/types.ts
Normal file
27
components/_Interface/types.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { Href } from "expo-router";
|
||||||
|
|
||||||
|
export { ICustomTab, ITabs, IMenuDrawerItem };
|
||||||
|
|
||||||
|
interface ICustomTab {
|
||||||
|
icon: string;
|
||||||
|
label: string;
|
||||||
|
isActive: boolean;
|
||||||
|
onPress: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ITabs {
|
||||||
|
id: string;
|
||||||
|
icon: string;
|
||||||
|
activeIcon: string;
|
||||||
|
label: string;
|
||||||
|
path: Href;
|
||||||
|
isActive: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IMenuDrawerItem {
|
||||||
|
icon: string;
|
||||||
|
label: string;
|
||||||
|
path?: string;
|
||||||
|
color?: string;
|
||||||
|
}
|
||||||
@@ -1,48 +1,111 @@
|
|||||||
import { Styles } from "@/styles/global-styles";
|
import { MainColor } from "@/constants/color-palet";
|
||||||
import { ImageBackground, ScrollView, View } from "react-native";
|
import { GStyles } from "@/styles/global-styles";
|
||||||
import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context";
|
import {
|
||||||
|
ImageBackground,
|
||||||
|
Keyboard,
|
||||||
|
KeyboardAvoidingView,
|
||||||
|
Platform,
|
||||||
|
ScrollView,
|
||||||
|
TouchableWithoutFeedback,
|
||||||
|
View,
|
||||||
|
} from "react-native";
|
||||||
|
import { SafeAreaView } from "react-native-safe-area-context";
|
||||||
|
|
||||||
interface ViewWrapperProps {
|
interface ViewWrapperProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
withBackground?: boolean;
|
withBackground?: boolean;
|
||||||
tabBarComponent?: React.ReactNode;
|
footerComponent?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ViewWrapper = ({
|
const ViewWrapper = ({
|
||||||
children,
|
children,
|
||||||
withBackground = false,
|
withBackground = false,
|
||||||
tabBarComponent,
|
footerComponent,
|
||||||
}: ViewWrapperProps) => {
|
}: ViewWrapperProps) => {
|
||||||
const assetBackground = require("../../assets/images/main-background.png");
|
const assetBackground = require("../../assets/images/main-background.png");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SafeAreaProvider>
|
<>
|
||||||
<SafeAreaView
|
<KeyboardAvoidingView
|
||||||
edges={[
|
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
||||||
"bottom",
|
style={{ flex: 1, backgroundColor: MainColor.darkblue }}
|
||||||
// "top",
|
|
||||||
]}
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
// paddingTop: StatusBar.currentHeight,
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<ScrollView contentContainerStyle={{ flexGrow: 1 }}>
|
<ScrollView
|
||||||
{withBackground ? (
|
contentContainerStyle={{ flexGrow: 1 }}
|
||||||
<ImageBackground
|
keyboardShouldPersistTaps="handled"
|
||||||
source={assetBackground}
|
>
|
||||||
resizeMode="cover"
|
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
|
||||||
style={Styles.imageBackground}
|
<View style={{ flex: 1 }}>
|
||||||
>
|
{withBackground ? (
|
||||||
<View style={Styles.containerWithBackground}>{children}</View>
|
<ImageBackground
|
||||||
</ImageBackground>
|
source={assetBackground}
|
||||||
) : (
|
resizeMode="cover"
|
||||||
<View style={Styles.container}>{children}</View>
|
style={GStyles.imageBackground}
|
||||||
)}
|
>
|
||||||
|
<View style={GStyles.containerWithBackground}>
|
||||||
|
{children}
|
||||||
|
</View>
|
||||||
|
</ImageBackground>
|
||||||
|
) : (
|
||||||
|
<View style={GStyles.container}>{children}</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</TouchableWithoutFeedback>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
{tabBarComponent}
|
|
||||||
</SafeAreaView>
|
{footerComponent ? (
|
||||||
</SafeAreaProvider>
|
<SafeAreaView
|
||||||
|
edges={["bottom"]}
|
||||||
|
style={{
|
||||||
|
backgroundColor: MainColor.darkblue,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{footerComponent}
|
||||||
|
</SafeAreaView>
|
||||||
|
) : (
|
||||||
|
<SafeAreaView
|
||||||
|
edges={["bottom"]}
|
||||||
|
style={{ backgroundColor: MainColor.darkblue }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</KeyboardAvoidingView>
|
||||||
|
|
||||||
|
{/* <SafeAreaView
|
||||||
|
edges={["bottom"]}
|
||||||
|
style={{ flex: 1, backgroundColor: MainColor.soft_darkblue }}
|
||||||
|
>
|
||||||
|
<KeyboardAvoidingView
|
||||||
|
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
||||||
|
style={{ flex: 1 }}
|
||||||
|
>
|
||||||
|
<ScrollView contentContainerStyle={{ flexGrow: 1 }}>
|
||||||
|
{withBackground ? (
|
||||||
|
<ImageBackground
|
||||||
|
source={assetBackground}
|
||||||
|
resizeMode="cover"
|
||||||
|
style={GStyles.imageBackground}
|
||||||
|
>
|
||||||
|
<View style={GStyles.containerWithBackground}>{children}</View>
|
||||||
|
</ImageBackground>
|
||||||
|
) : (
|
||||||
|
<View style={GStyles.container}>{children}</View>
|
||||||
|
)}
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
{footerComponent ? (
|
||||||
|
<SafeAreaView
|
||||||
|
edges={["bottom"]}
|
||||||
|
style={{
|
||||||
|
// flex: 1,
|
||||||
|
backgroundColor: MainColor.darkblue,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{footerComponent}
|
||||||
|
</SafeAreaView>
|
||||||
|
) : null}
|
||||||
|
</KeyboardAvoidingView>
|
||||||
|
</SafeAreaView> */}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
51
components/_ShareComponent/ViewWrapper2.tsx
Normal file
51
components/_ShareComponent/ViewWrapper2.tsx
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {
|
||||||
|
View,
|
||||||
|
ScrollView,
|
||||||
|
KeyboardAvoidingView,
|
||||||
|
Platform,
|
||||||
|
TouchableWithoutFeedback,
|
||||||
|
Keyboard,
|
||||||
|
StyleSheet,
|
||||||
|
} from "react-native";
|
||||||
|
|
||||||
|
import { SafeAreaView } from "react-native-safe-area-context"; // <- Diubah ke sini
|
||||||
|
|
||||||
|
interface ViewWrapperProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
footerComponent?: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Try_ViewWrapper = ({ children, footerComponent }: ViewWrapperProps) => {
|
||||||
|
return (
|
||||||
|
<KeyboardAvoidingView
|
||||||
|
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
||||||
|
style={{ flex: 1 }}
|
||||||
|
>
|
||||||
|
<ScrollView contentContainerStyle={{ flexGrow: 1 }}>
|
||||||
|
<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
|
||||||
|
<View style={{ flex: 1 }}>{children}</View>
|
||||||
|
</TouchableWithoutFeedback>
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
{/* Footer Component */}
|
||||||
|
{footerComponent && (
|
||||||
|
<SafeAreaView edges={["bottom"]} style={styles.footerContainer}>
|
||||||
|
{footerComponent}
|
||||||
|
</SafeAreaView>
|
||||||
|
)}
|
||||||
|
</KeyboardAvoidingView>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Try_ViewWrapper;
|
||||||
|
|
||||||
|
// File: ViewWrapper.styles.js
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
footerContainer: {
|
||||||
|
backgroundColor: "#fff",
|
||||||
|
borderTopWidth: 1,
|
||||||
|
borderColor: "#ddd",
|
||||||
|
},
|
||||||
|
});
|
||||||
66
components/index.ts
Normal file
66
components/index.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
// Alert
|
||||||
|
import AlertCustom from "./Alert/AlertCustom";
|
||||||
|
// Button
|
||||||
|
import LeftButtonCustom from "./Button/BackButton";
|
||||||
|
import ButtonCenteredOnly from "./Button/ButtonCenteredOnly";
|
||||||
|
import ButtonCustom from "./Button/ButtonCustom";
|
||||||
|
// Drawer
|
||||||
|
import DrawerCustom from "./Drawer/DrawerCustom";
|
||||||
|
import MenuDrawerDynamicGrid from "./Drawer/MenuDrawerDynamicGird";
|
||||||
|
// ShareComponent
|
||||||
|
import Spacing from "./_ShareComponent/Spacing";
|
||||||
|
import ViewWrapper from "./_ShareComponent/ViewWrapper";
|
||||||
|
// Text
|
||||||
|
import TextCustom from "./Text/TextCustom";
|
||||||
|
// TextInput
|
||||||
|
import TextInputCustom from "./TextInput/TextInputCustom";
|
||||||
|
// TextArea
|
||||||
|
import TextAreaCustom from "./TextArea/TextAreaCustom";
|
||||||
|
// Grid
|
||||||
|
import Grid from "./Grid/GridCustom";
|
||||||
|
// Box
|
||||||
|
import BaseBox from "./Box/BaseBox";
|
||||||
|
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,
|
||||||
|
// Image
|
||||||
|
AvatarCustom,
|
||||||
|
LandscapeFrameUploaded,
|
||||||
|
// Button
|
||||||
|
ButtonCustom,
|
||||||
|
LeftButtonCustom as BackButton,
|
||||||
|
ButtonCenteredOnly,
|
||||||
|
// Box
|
||||||
|
BaseBox,
|
||||||
|
BoxButtonOnFooter,
|
||||||
|
InformationBox,
|
||||||
|
// Drawer
|
||||||
|
DrawerCustom,
|
||||||
|
// Grid
|
||||||
|
Grid,
|
||||||
|
MenuDrawerDynamicGrid,
|
||||||
|
// Select
|
||||||
|
SelectCustom,
|
||||||
|
// ShareComponent
|
||||||
|
Spacing,
|
||||||
|
// Stack
|
||||||
|
StackCustom,
|
||||||
|
// TextArea
|
||||||
|
TextAreaCustom,
|
||||||
|
// Text
|
||||||
|
TextCustom,
|
||||||
|
// TextInput
|
||||||
|
TextInputCustom,
|
||||||
|
// ViewWrapper
|
||||||
|
ViewWrapper,
|
||||||
|
};
|
||||||
@@ -3,22 +3,27 @@ export const MainColor = {
|
|||||||
darkblue: "#001D3D",
|
darkblue: "#001D3D",
|
||||||
soft_darkblue: "#0e3763",
|
soft_darkblue: "#0e3763",
|
||||||
yellow: "#E1B525",
|
yellow: "#E1B525",
|
||||||
white: "#D4D0D0",
|
|
||||||
red: "#FF4B4C",
|
red: "#FF4B4C",
|
||||||
orange: "#FF7043",
|
orange: "#FF7043",
|
||||||
green: "#4CAF4F",
|
green: "#4CAF4F",
|
||||||
login: "#EDEBEBFF",
|
white_gray: "#D4D0D0",
|
||||||
disabled: "#606360",
|
text_input: "#EDEBEBFF",
|
||||||
|
placeholder: "#888",
|
||||||
|
white: "#ffffff",
|
||||||
|
// disabled color
|
||||||
|
disabled: "#777",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AccentColor = {
|
export const AccentColor = {
|
||||||
blackgray: "#333533FF",
|
blackgray: "#aaa",
|
||||||
darkblue: "#002E59",
|
darkblue: "#002E59",
|
||||||
blue: "#00447D",
|
blue: "#00447D",
|
||||||
softblue: "#007CBA",
|
softblue: "#007CBA",
|
||||||
skyblue: "#00BFFF",
|
skyblue: "#00BFFF",
|
||||||
yellow: "#F8A824",
|
yellow: "#F8A824",
|
||||||
white: "#FEFFFE",
|
white: "#FEFFFE",
|
||||||
|
// disable color
|
||||||
|
disabledBorder: "#aaa",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AdminColor = {
|
export const AdminColor = {
|
||||||
|
|||||||
19
constants/constans-value.ts
Normal file
19
constants/constans-value.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
export {
|
||||||
|
TEXT_SIZE_SMALL,
|
||||||
|
TEXT_SIZE_MEDIUM,
|
||||||
|
TEXT_SIZE_LARGE,
|
||||||
|
ICON_SIZE_SMALL,
|
||||||
|
ICON_SIZE_MEDIUM,
|
||||||
|
DRAWER_HEIGHT,
|
||||||
|
RADIUS_BUTTON,
|
||||||
|
ICON_SIZE_BUTTON,
|
||||||
|
};
|
||||||
|
|
||||||
|
const TEXT_SIZE_SMALL = 12;
|
||||||
|
const TEXT_SIZE_MEDIUM = 14;
|
||||||
|
const TEXT_SIZE_LARGE = 16;
|
||||||
|
const ICON_SIZE_SMALL = 20;
|
||||||
|
const ICON_SIZE_MEDIUM = 24;
|
||||||
|
const DRAWER_HEIGHT = 500; // tinggi drawer5
|
||||||
|
const RADIUS_BUTTON = 50
|
||||||
|
const ICON_SIZE_BUTTON = 18
|
||||||
6
constants/dummy-image-value.ts
Normal file
6
constants/dummy-image-value.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
const DUMMY_IMAGE = {
|
||||||
|
avatar: require("@/assets/images/dummy/dummy-avatar.png"),
|
||||||
|
background: require("@/assets/images/dummy/dummy-image-background.jpg"),
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DUMMY_IMAGE;
|
||||||
10
constants/radius-value.ts
Normal file
10
constants/radius-value.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
// constants/radius.ts
|
||||||
|
|
||||||
|
export const radiusMap = {
|
||||||
|
xs: 2,
|
||||||
|
sm: 4,
|
||||||
|
md: 6,
|
||||||
|
lg: 8,
|
||||||
|
xl: 12,
|
||||||
|
full: 100,
|
||||||
|
} as const;
|
||||||
1
eas.build.android
Normal file
1
eas.build.android
Normal file
@@ -0,0 +1 @@
|
|||||||
|
eas build --profile preview
|
||||||
7
eas.json
7
eas.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"cli": {
|
"cli": {
|
||||||
"version": ">= 16.12.0",
|
"version": ">= 16.10.0",
|
||||||
"appVersionSource": "remote"
|
"appVersionSource": "remote"
|
||||||
},
|
},
|
||||||
"build": {
|
"build": {
|
||||||
@@ -9,7 +9,10 @@
|
|||||||
"distribution": "internal"
|
"distribution": "internal"
|
||||||
},
|
},
|
||||||
"preview": {
|
"preview": {
|
||||||
"distribution": "internal"
|
"distribution": "internal",
|
||||||
|
"android": {
|
||||||
|
"buildType": "apk"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"production": {
|
"production": {
|
||||||
"autoIncrement": true
|
"autoIncrement": true
|
||||||
|
|||||||
100
lib/dummy-data/master-bidang-bisnis.ts
Normal file
100
lib/dummy-data/master-bidang-bisnis.ts
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
const dummyMasterBidangBisnis = [
|
||||||
|
{
|
||||||
|
id: "1",
|
||||||
|
name: "Teknologi dan Digital",
|
||||||
|
slug: "teknologi_dan_digital",
|
||||||
|
active: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.403Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.403Z",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "2",
|
||||||
|
name: "Kuliner",
|
||||||
|
slug: "kuliner",
|
||||||
|
active: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.424Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.424Z",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "3",
|
||||||
|
name: "Fashion dan Kecantikan",
|
||||||
|
slug: "fashion_dan_kecantikan",
|
||||||
|
active: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.442Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.442Z",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "4",
|
||||||
|
name: "Otomotif",
|
||||||
|
slug: "otomotif",
|
||||||
|
active: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.459Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.459Z",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "5",
|
||||||
|
name: "Industri Kreatif",
|
||||||
|
slug: "industri_kreatif",
|
||||||
|
active: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.471Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.471Z",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "6",
|
||||||
|
name: "Konstruksi dan Pertukangan",
|
||||||
|
slug: "konstruksi_dan_pertukangan",
|
||||||
|
active: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.483Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.483Z",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "7",
|
||||||
|
name: "Agribisnis dan Pertanian",
|
||||||
|
slug: "agribisnis_dan_pertanian",
|
||||||
|
active: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.492Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.492Z",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "8",
|
||||||
|
name: "Jasa Umum",
|
||||||
|
slug: "jasa_umum",
|
||||||
|
active: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.502Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.502Z",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "9",
|
||||||
|
name: "Edukasi dan Pelatihan",
|
||||||
|
slug: "edukasi_dan_pelatihan",
|
||||||
|
active: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.517Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.517Z",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "10",
|
||||||
|
name: "Keuangan dan Investasi",
|
||||||
|
slug: "keuangan_dan_investasi",
|
||||||
|
active: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.527Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.527Z",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "11",
|
||||||
|
name: "Perdagangan Umum",
|
||||||
|
slug: "perdagangan_umum",
|
||||||
|
active: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.537Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.537Z",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "12",
|
||||||
|
name: "Pariwisata dan Hospitality",
|
||||||
|
slug: "pariwisata_dan_hospitality",
|
||||||
|
active: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.547Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.547Z",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default dummyMasterBidangBisnis;
|
||||||
734
lib/dummy-data/master-sub-bidang-bisnis.ts
Normal file
734
lib/dummy-data/master-sub-bidang-bisnis.ts
Normal file
@@ -0,0 +1,734 @@
|
|||||||
|
const dummyMasterSubBidangBisnis = [
|
||||||
|
{
|
||||||
|
id: "TEK-01",
|
||||||
|
name: "Software Developer",
|
||||||
|
slug: "software_developer",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.406Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.406Z",
|
||||||
|
masterBidangBisnisId: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "TEK-02",
|
||||||
|
name: "Web Developer",
|
||||||
|
slug: "web_developer",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.408Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.408Z",
|
||||||
|
masterBidangBisnisId: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "TEK-03",
|
||||||
|
name: "Mobile App Developer",
|
||||||
|
slug: "mobile_app_developer",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.411Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.411Z",
|
||||||
|
masterBidangBisnisId: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "TEK-04",
|
||||||
|
name: "Konsultan IT",
|
||||||
|
slug: "konsultan_it",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.413Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.413Z",
|
||||||
|
masterBidangBisnisId: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "TEK-05",
|
||||||
|
name: "Digital Marketing",
|
||||||
|
slug: "digital_marketing",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.415Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.415Z",
|
||||||
|
masterBidangBisnisId: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "TEK-06",
|
||||||
|
name: "Cybersecurity",
|
||||||
|
slug: "cybersecurity",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.417Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.417Z",
|
||||||
|
masterBidangBisnisId: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "TEK-07",
|
||||||
|
name: "AI & Machine Learning Services",
|
||||||
|
slug: "ai_and_machine_learning_services",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.419Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.419Z",
|
||||||
|
masterBidangBisnisId: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "TEK-08",
|
||||||
|
name: "Data Analyst/Data Scientist",
|
||||||
|
slug: "data_analyst_data_scientist",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.421Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.421Z",
|
||||||
|
masterBidangBisnisId: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "TEK-09",
|
||||||
|
name: "Blockchain Developer",
|
||||||
|
slug: "blockchain_developer",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.423Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.423Z",
|
||||||
|
masterBidangBisnisId: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "KUL-01",
|
||||||
|
name: "Restoran",
|
||||||
|
slug: "restoran",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.426Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.426Z",
|
||||||
|
masterBidangBisnisId: "2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "KUL-02",
|
||||||
|
name: "Kafe",
|
||||||
|
slug: "kafe",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.428Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.428Z",
|
||||||
|
masterBidangBisnisId: "2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "KUL-03",
|
||||||
|
name: "Warung Makan",
|
||||||
|
slug: "warung_makan",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.431Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.431Z",
|
||||||
|
masterBidangBisnisId: "2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "KUL-04",
|
||||||
|
name: "Catering",
|
||||||
|
slug: "catering",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.433Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.433Z",
|
||||||
|
masterBidangBisnisId: "2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "KUL-05",
|
||||||
|
name: "Food Truck",
|
||||||
|
slug: "food_truck",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.435Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.435Z",
|
||||||
|
masterBidangBisnisId: "2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "KUL-06",
|
||||||
|
name: "Minuman Kekinian",
|
||||||
|
slug: "minuman_kekinian",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.437Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.437Z",
|
||||||
|
masterBidangBisnisId: "2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "KUL-07",
|
||||||
|
name: "Toko Roti & Kue",
|
||||||
|
slug: "toko_roti_kue",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.438Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.438Z",
|
||||||
|
masterBidangBisnisId: "2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "KUL-08",
|
||||||
|
name: "Supplier Bahan Makanan",
|
||||||
|
slug: "supplier_bahan_makanan",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.440Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.440Z",
|
||||||
|
masterBidangBisnisId: "2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "FAS-01",
|
||||||
|
name: "Pakaian Dewasa & Anak",
|
||||||
|
slug: "pakaian_dewasa_anak",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.444Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.444Z",
|
||||||
|
masterBidangBisnisId: "3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "FAS-02",
|
||||||
|
name: "Butik",
|
||||||
|
slug: "butik",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.445Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.445Z",
|
||||||
|
masterBidangBisnisId: "3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "FAS-03",
|
||||||
|
name: "Desainer Fashion",
|
||||||
|
slug: "desainer_fashion",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.448Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.448Z",
|
||||||
|
masterBidangBisnisId: "3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "FAS-04",
|
||||||
|
name: "Aksesoris & Perhiasan",
|
||||||
|
slug: "aksesoris_perhiasan",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.449Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.449Z",
|
||||||
|
masterBidangBisnisId: "3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "FAS-05",
|
||||||
|
name: "Kosmetik",
|
||||||
|
slug: "kosmetik",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.451Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.451Z",
|
||||||
|
masterBidangBisnisId: "3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "FAS-06",
|
||||||
|
name: "Skincare",
|
||||||
|
slug: "skincare",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.453Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.453Z",
|
||||||
|
masterBidangBisnisId: "3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "FAS-07",
|
||||||
|
name: "Salon Kecantikan",
|
||||||
|
slug: "salon_kecantikan",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.455Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.455Z",
|
||||||
|
masterBidangBisnisId: "3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "FAS-08",
|
||||||
|
name: "Barbershop",
|
||||||
|
slug: "barbershop",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.456Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.456Z",
|
||||||
|
masterBidangBisnisId: "3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "OTO-01",
|
||||||
|
name: "Jual Beli Mobil/Motor",
|
||||||
|
slug: "jual_beli_mobil_motor",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.461Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.461Z",
|
||||||
|
masterBidangBisnisId: "4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "OTO-02",
|
||||||
|
name: "Bengkel Mobil/Motor",
|
||||||
|
slug: "bengkel_mobil_motor",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.463Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.463Z",
|
||||||
|
masterBidangBisnisId: "4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "OTO-03",
|
||||||
|
name: "Aksesori Kendaraan",
|
||||||
|
slug: "aksesori_kendaraan",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.465Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.465Z",
|
||||||
|
masterBidangBisnisId: "4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "OTO-04",
|
||||||
|
name: "Rental Kendaraan",
|
||||||
|
slug: "rental_kendaraan",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.466Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.466Z",
|
||||||
|
masterBidangBisnisId: "4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "OTO-05",
|
||||||
|
name: "Cuci Mobil/Motor",
|
||||||
|
slug: "cuci_mobil_motor",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.468Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.468Z",
|
||||||
|
masterBidangBisnisId: "4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "OTO-06",
|
||||||
|
name: "Spare Part & Mesin Mobil",
|
||||||
|
slug: "spare_part_mesin_mobil",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.469Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.469Z",
|
||||||
|
masterBidangBisnisId: "4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "INK-01",
|
||||||
|
name: "Fotografi & Videografi",
|
||||||
|
slug: "fotografi_videografi",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.472Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.472Z",
|
||||||
|
masterBidangBisnisId: "5",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "INK-02",
|
||||||
|
name: "Event Organizer",
|
||||||
|
slug: "event_organizer",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.473Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.473Z",
|
||||||
|
masterBidangBisnisId: "5",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "INK-03",
|
||||||
|
name: "Desain Grafis",
|
||||||
|
slug: "desain_grafis",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.475Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.475Z",
|
||||||
|
masterBidangBisnisId: "5",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "INK-04",
|
||||||
|
name: "Advertising & Branding",
|
||||||
|
slug: "advertising_branding",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.476Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.476Z",
|
||||||
|
masterBidangBisnisId: "5",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "INK-05",
|
||||||
|
name: "Jasa Percetakan",
|
||||||
|
slug: "jasa_percetakan",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.477Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.477Z",
|
||||||
|
masterBidangBisnisId: "5",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "INK-06",
|
||||||
|
name: "Dekorasi & Wedding Planner",
|
||||||
|
slug: "dekorasi_wedding_planner",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.480Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.480Z",
|
||||||
|
masterBidangBisnisId: "5",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "INK-07",
|
||||||
|
name: "Studio Musik & Produksi",
|
||||||
|
slug: "studio_musik_produksi",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.481Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.481Z",
|
||||||
|
masterBidangBisnisId: "5",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "KON-01",
|
||||||
|
name: "Kontraktor Bangunan",
|
||||||
|
slug: "kontraktor_bangunan",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.484Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.484Z",
|
||||||
|
masterBidangBisnisId: "6",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "KON-02",
|
||||||
|
name: "Arsitek",
|
||||||
|
slug: "arsitek",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.486Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.486Z",
|
||||||
|
masterBidangBisnisId: "6",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "KON-03",
|
||||||
|
name: "Desain Interior",
|
||||||
|
slug: "desain_interior",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.487Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.487Z",
|
||||||
|
masterBidangBisnisId: "6",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "KON-04",
|
||||||
|
name: "Supplier Material Bangunan",
|
||||||
|
slug: "supplier_material_bangunan",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.489Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.489Z",
|
||||||
|
masterBidangBisnisId: "6",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "KON-05",
|
||||||
|
name: "Tukang & Renovasi Rumah",
|
||||||
|
slug: "tukang_renovasi_rumah",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.490Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.490Z",
|
||||||
|
masterBidangBisnisId: "6",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "AGR-01",
|
||||||
|
name: "Perkebunan",
|
||||||
|
slug: "perkebunan",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.493Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.493Z",
|
||||||
|
masterBidangBisnisId: "7",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "AGR-02",
|
||||||
|
name: "Peternakan",
|
||||||
|
slug: "peternakan",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.496Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.496Z",
|
||||||
|
masterBidangBisnisId: "7",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "AGR-03",
|
||||||
|
name: "Perikanan",
|
||||||
|
slug: "perikanan",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.497Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.497Z",
|
||||||
|
masterBidangBisnisId: "7",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "AGR-04",
|
||||||
|
name: "Supplier Bibit & Pupuk",
|
||||||
|
slug: "supplier_bibit_pupuk",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.498Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.498Z",
|
||||||
|
masterBidangBisnisId: "7",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "AGR-05",
|
||||||
|
name: "Hasil Tani Organik",
|
||||||
|
slug: "hasil_tani_organik",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.500Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.500Z",
|
||||||
|
masterBidangBisnisId: "7",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "AGR-06",
|
||||||
|
name: "Alat & Mesin Pertanian",
|
||||||
|
slug: "alat_mesin_pertanian",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.501Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.501Z",
|
||||||
|
masterBidangBisnisId: "7",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "JAS-01",
|
||||||
|
name: "Jasa Kebersihan",
|
||||||
|
slug: "jasa_kebersihan",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.504Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.504Z",
|
||||||
|
masterBidangBisnisId: "8",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "JAS-02",
|
||||||
|
name: "Laundry",
|
||||||
|
slug: "laundry",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.505Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.505Z",
|
||||||
|
masterBidangBisnisId: "8",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "JAS-03",
|
||||||
|
name: "Penitipan Anak",
|
||||||
|
slug: "penitipan_anak",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.506Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.506Z",
|
||||||
|
masterBidangBisnisId: "8",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "JAS-04",
|
||||||
|
name: "Jasa Keamanan",
|
||||||
|
slug: "jasa_keamanan",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.508Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.508Z",
|
||||||
|
masterBidangBisnisId: "8",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "JAS-05",
|
||||||
|
name: "Jasa Pengiriman/Logistik",
|
||||||
|
slug: "jasa_pengiriman_logistik",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.511Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.511Z",
|
||||||
|
masterBidangBisnisId: "8",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "JAS-06",
|
||||||
|
name: "Jasa Ekspedisi",
|
||||||
|
slug: "jasa_ekspedisi",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.513Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.513Z",
|
||||||
|
masterBidangBisnisId: "8",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "JAS-07",
|
||||||
|
name: "Konsultan Bisnis",
|
||||||
|
slug: "konsultan_bisnis",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.514Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.514Z",
|
||||||
|
masterBidangBisnisId: "8",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "JAS-08",
|
||||||
|
name: "Jasa Hukum/Legal",
|
||||||
|
slug: "jasa_hukum_legal",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.516Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.516Z",
|
||||||
|
masterBidangBisnisId: "8",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "EDU-01",
|
||||||
|
name: "Bimbingan Belajar",
|
||||||
|
slug: "bimbingan_belajar",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.518Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.518Z",
|
||||||
|
masterBidangBisnisId: "9",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "EDU-02",
|
||||||
|
name: "Kursus Bahasa",
|
||||||
|
slug: "kursus_bahasa",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.520Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.520Z",
|
||||||
|
masterBidangBisnisId: "9",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "EDU-03",
|
||||||
|
name: "Pelatihan Digital/Skill",
|
||||||
|
slug: "pelatihan_digital_skill",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.521Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.521Z",
|
||||||
|
masterBidangBisnisId: "9",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "EDU-04",
|
||||||
|
name: "LPK (Lembaga Pelatihan Kerja)",
|
||||||
|
slug: "lpk_lembaga_pelatihan_kerja",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.523Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.523Z",
|
||||||
|
masterBidangBisnisId: "9",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "EDU-05",
|
||||||
|
name: "Homeschooling",
|
||||||
|
slug: "homeschooling",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.525Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.525Z",
|
||||||
|
masterBidangBisnisId: "9",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "KEU-01",
|
||||||
|
name: "Koperasi",
|
||||||
|
slug: "koperasi",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.529Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.529Z",
|
||||||
|
masterBidangBisnisId: "10",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "KEU-02",
|
||||||
|
name: "FinTEKh",
|
||||||
|
slug: "finTEKh",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.530Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.530Z",
|
||||||
|
masterBidangBisnisId: "10",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "KEU-03",
|
||||||
|
name: "Konsultan Keuangan",
|
||||||
|
slug: "konsultan_keuangan",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.531Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.531Z",
|
||||||
|
masterBidangBisnisId: "10",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "KEU-04",
|
||||||
|
name: "Investasi & Saham",
|
||||||
|
slug: "investasi_saham",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.532Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.532Z",
|
||||||
|
masterBidangBisnisId: "10",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "KEU-05",
|
||||||
|
name: "Asuransi",
|
||||||
|
slug: "asuransi",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.534Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.534Z",
|
||||||
|
masterBidangBisnisId: "10",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "KEU-06",
|
||||||
|
name: "Akuntan Publik",
|
||||||
|
slug: "akuntan_publik",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.535Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.535Z",
|
||||||
|
masterBidangBisnisId: "10",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "PER-01",
|
||||||
|
name: "Toko Kelontong",
|
||||||
|
slug: "toko_kelontong",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.538Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.538Z",
|
||||||
|
masterBidangBisnisId: "11",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "PER-02",
|
||||||
|
name: "Minimarket",
|
||||||
|
slug: "minimarket",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.540Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.540Z",
|
||||||
|
masterBidangBisnisId: "11",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "PER-03",
|
||||||
|
name: "Grosir & Distributor",
|
||||||
|
slug: "grosir_distributor",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.541Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.541Z",
|
||||||
|
masterBidangBisnisId: "11",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "PER-04",
|
||||||
|
name: "Dropshipper & Reseller",
|
||||||
|
slug: "dropshipper_reseller",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.543Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.543Z",
|
||||||
|
masterBidangBisnisId: "11",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "PER-05",
|
||||||
|
name: "Marketplace & E-commerce",
|
||||||
|
slug: "marketplace_e_commerce",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.544Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.544Z",
|
||||||
|
masterBidangBisnisId: "11",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "PER-06",
|
||||||
|
name: "Supplier Produk",
|
||||||
|
slug: "supplier_produk",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.546Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.546Z",
|
||||||
|
masterBidangBisnisId: "11",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "PAR-01",
|
||||||
|
name: "Agen Travel",
|
||||||
|
slug: "agen_travel",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.549Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.549Z",
|
||||||
|
masterBidangBisnisId: "12",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "PAR-02",
|
||||||
|
name: "Tour Guide",
|
||||||
|
slug: "tour_guide",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.550Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.550Z",
|
||||||
|
masterBidangBisnisId: "12",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "PAR-03",
|
||||||
|
name: "Villa & Penginapan",
|
||||||
|
slug: "villa_penginapan",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.551Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.551Z",
|
||||||
|
masterBidangBisnisId: "12",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "PAR-04",
|
||||||
|
name: "Homestay",
|
||||||
|
slug: "homestay",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.552Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.552Z",
|
||||||
|
masterBidangBisnisId: "12",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "PAR-05",
|
||||||
|
name: "Hotel",
|
||||||
|
slug: "hotel",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.554Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.554Z",
|
||||||
|
masterBidangBisnisId: "12",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "PAR-06",
|
||||||
|
name: "Sewa Motor/Travel",
|
||||||
|
slug: "sewa_motor_travel",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.555Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.555Z",
|
||||||
|
masterBidangBisnisId: "12",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "PAR-07",
|
||||||
|
name: "Sovenir & Oleh-Oleh",
|
||||||
|
slug: "sovenir_oleh_oleh",
|
||||||
|
isActive: true,
|
||||||
|
createdAt: "2025-06-16T09:57:16.557Z",
|
||||||
|
updatedAt: "2025-06-16T09:57:16.557Z",
|
||||||
|
masterBidangBisnisId: "12",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
export default dummyMasterSubBidangBisnis;
|
||||||
0
lib/index.ts
Normal file
0
lib/index.ts
Normal file
21
package.json
21
package.json
@@ -13,26 +13,29 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/vector-icons": "^14.1.0",
|
"@expo/vector-icons": "^14.1.0",
|
||||||
"@react-navigation/bottom-tabs": "^7.4.2",
|
"@react-navigation/bottom-tabs": "^7.4.2",
|
||||||
|
"@react-navigation/drawer": "^7.5.2",
|
||||||
"@react-navigation/elements": "^2.3.8",
|
"@react-navigation/elements": "^2.3.8",
|
||||||
"@react-navigation/native": "^7.1.6",
|
"@react-navigation/native": "^7.1.6",
|
||||||
"@react-navigation/native-stack": "^7.3.21",
|
"@react-navigation/native-stack": "^7.3.21",
|
||||||
"@types/react-native-vector-icons": "^6.4.18",
|
"@types/react-native-vector-icons": "^6.4.18",
|
||||||
"expo": "~53.0.12",
|
"expo": "53.0.17",
|
||||||
"expo-blur": "~14.1.5",
|
"expo-blur": "~14.1.5",
|
||||||
"expo-constants": "~17.1.6",
|
"expo-camera": "~16.1.10",
|
||||||
"expo-font": "~13.3.1",
|
"expo-constants": "~17.1.7",
|
||||||
|
"expo-font": "~13.3.2",
|
||||||
"expo-haptics": "~14.1.4",
|
"expo-haptics": "~14.1.4",
|
||||||
"expo-image": "~2.3.0",
|
"expo-image": "~2.3.2",
|
||||||
"expo-linking": "~7.1.5",
|
"expo-image-picker": "~16.1.4",
|
||||||
"expo-router": "~5.1.0",
|
"expo-linking": "~7.1.7",
|
||||||
"expo-splash-screen": "~0.30.9",
|
"expo-router": "~5.1.3",
|
||||||
|
"expo-splash-screen": "~0.30.10",
|
||||||
"expo-status-bar": "~2.2.3",
|
"expo-status-bar": "~2.2.3",
|
||||||
"expo-symbols": "~0.4.5",
|
"expo-symbols": "~0.4.5",
|
||||||
"expo-system-ui": "~5.0.9",
|
"expo-system-ui": "~5.0.10",
|
||||||
"expo-web-browser": "~14.2.0",
|
"expo-web-browser": "~14.2.0",
|
||||||
"react": "19.0.0",
|
"react": "19.0.0",
|
||||||
"react-dom": "19.0.0",
|
"react-dom": "19.0.0",
|
||||||
"react-native": "0.79.4",
|
"react-native": "0.79.5",
|
||||||
"react-native-gesture-handler": "~2.24.0",
|
"react-native-gesture-handler": "~2.24.0",
|
||||||
"react-native-international-phone-number": "^0.9.3",
|
"react-native-international-phone-number": "^0.9.3",
|
||||||
"react-native-otp-entry": "^1.8.5",
|
"react-native-otp-entry": "^1.8.5",
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
|
import ButtonCustom from "@/components/Button/ButtonCustom";
|
||||||
|
import Spacing from "@/components/_ShareComponent/Spacing";
|
||||||
|
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
||||||
import { MainColor } from "@/constants/color-palet";
|
import { MainColor } from "@/constants/color-palet";
|
||||||
import { Styles } from "@/styles/global-styles";
|
import { GStyles } from "@/styles/global-styles";
|
||||||
import { router } from "expo-router";
|
import { router } from "expo-router";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Text, View } from "react-native";
|
import { Text, View } from "react-native";
|
||||||
import PhoneInput, { ICountry } from "react-native-international-phone-number";
|
import PhoneInput, { ICountry } from "react-native-international-phone-number";
|
||||||
import ButtonCustom from "@/components/Button/ButtonCustom";
|
|
||||||
import Spacing from "@/components/_ShareComponent/Spacing";
|
|
||||||
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
|
||||||
|
|
||||||
|
|
||||||
export default function LoginView() {
|
export default function LoginView() {
|
||||||
const [selectedCountry, setSelectedCountry] = useState<null | ICountry>(null);
|
const [selectedCountry, setSelectedCountry] = useState<null | ICountry>(null);
|
||||||
@@ -24,18 +23,27 @@ export default function LoginView() {
|
|||||||
function handleLogin() {
|
function handleLogin() {
|
||||||
const callingCode = selectedCountry?.callingCode.replace(/^\+/, "") || "";
|
const callingCode = selectedCountry?.callingCode.replace(/^\+/, "") || "";
|
||||||
const fixNumber = callingCode + inputValue;
|
const fixNumber = callingCode + inputValue;
|
||||||
console.log(fixNumber);
|
// console.log("fixNumber", fixNumber);
|
||||||
router.push("/verification");
|
|
||||||
|
const randomAlfabet = Math.random().toString(36).substring(2, 8);
|
||||||
|
const randomNumber = Math.floor(Math.random() * 1000000);
|
||||||
|
const id = randomAlfabet + randomNumber + fixNumber;
|
||||||
|
console.log("login user id :", id);
|
||||||
|
|
||||||
|
// router.navigate("/verification");
|
||||||
|
// router.navigate(`/(application)/(user)/profile/${id}`);
|
||||||
|
router.navigate("/(application)/(user)/home");
|
||||||
|
// router.navigate(`/(application)/profile/${id}/edit`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ViewWrapper withBackground>
|
<ViewWrapper withBackground>
|
||||||
<View style={Styles.authContainer}>
|
<View style={GStyles.authContainer}>
|
||||||
<View>
|
<View>
|
||||||
<View style={Styles.authContainerTitle}>
|
<View style={GStyles.authContainerTitle}>
|
||||||
<Text style={Styles.authSubTitle}>WELCOME TO</Text>
|
<Text style={GStyles.authSubTitle}>WELCOME TO</Text>
|
||||||
<Spacing height={5} />
|
<Spacing height={5} />
|
||||||
<Text style={Styles.authTitle}>HIPMI BADUNG APPS</Text>
|
<Text style={GStyles.authTitle}>HIPMI BADUNG APPS</Text>
|
||||||
<Spacing height={5} />
|
<Spacing height={5} />
|
||||||
</View>
|
</View>
|
||||||
<Spacing height={50} />
|
<Spacing height={50} />
|
||||||
@@ -47,7 +55,7 @@ export default function LoginView() {
|
|||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
fontWeight: "thin",
|
fontWeight: "thin",
|
||||||
fontStyle: "italic",
|
fontStyle: "italic",
|
||||||
color: MainColor.white,
|
color: MainColor.white_gray,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
powered by muku.id
|
powered by muku.id
|
||||||
@@ -65,13 +73,7 @@ export default function LoginView() {
|
|||||||
|
|
||||||
<Spacing height={20} />
|
<Spacing height={20} />
|
||||||
|
|
||||||
<ButtonCustom
|
<ButtonCustom onPress={handleLogin}>Login</ButtonCustom>
|
||||||
title="Login"
|
|
||||||
backgroundColor={MainColor.yellow}
|
|
||||||
textColor={MainColor.black}
|
|
||||||
radius={10}
|
|
||||||
onPress={handleLogin}
|
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
</ViewWrapper>
|
</ViewWrapper>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,20 +3,25 @@ import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
|||||||
import ButtonCustom from "@/components/Button/ButtonCustom";
|
import ButtonCustom from "@/components/Button/ButtonCustom";
|
||||||
import { TextInputCustom } from "@/components/TextInput/TextInputCustom";
|
import { TextInputCustom } from "@/components/TextInput/TextInputCustom";
|
||||||
import { MainColor } from "@/constants/color-palet";
|
import { MainColor } from "@/constants/color-palet";
|
||||||
import { Styles } from "@/styles/global-styles";
|
import { GStyles } from "@/styles/global-styles";
|
||||||
import { MaterialCommunityIcons } from "@expo/vector-icons";
|
import { MaterialCommunityIcons } from "@expo/vector-icons";
|
||||||
import { router } from "expo-router";
|
import { router } from "expo-router";
|
||||||
import { Text, View } from "react-native";
|
import { Text, View } from "react-native";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
export default function RegisterView() {
|
export default function RegisterView() {
|
||||||
|
const [username, setUsername] = useState("Bagas Banuna");
|
||||||
|
const handleRegister = () => {
|
||||||
|
console.log("Success register", username);
|
||||||
|
router.push("/(application)/(user)/home");
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ViewWrapper withBackground>
|
<ViewWrapper withBackground>
|
||||||
<View style={Styles.authContainer}>
|
<View style={GStyles.authContainer}>
|
||||||
<View>
|
<View>
|
||||||
<View style={Styles.authContainerTitle}>
|
<View style={GStyles.authContainerTitle}>
|
||||||
<Text style={Styles.authTitle}>REGISTRASI</Text>
|
<Text style={GStyles.authTitle}>REGISTRASI</Text>
|
||||||
<Spacing />
|
<Spacing />
|
||||||
<MaterialCommunityIcons
|
<MaterialCommunityIcons
|
||||||
name="account"
|
name="account"
|
||||||
@@ -25,35 +30,29 @@ export default function RegisterView() {
|
|||||||
/>
|
/>
|
||||||
<Spacing />
|
<Spacing />
|
||||||
|
|
||||||
<Text style={Styles.textLabel}>
|
<Text style={GStyles.textLabel}>
|
||||||
Anda akan terdaftar dengan nomor
|
Anda akan terdaftar dengan nomor
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={Styles.textLabel}>+6282xxxxxxxxx</Text>
|
<Text style={GStyles.textLabel}>+6282xxxxxxxxx</Text>
|
||||||
<Spacing />
|
<Spacing />
|
||||||
</View>
|
</View>
|
||||||
<TextInputCustom placeholder="Masukkan username" />
|
<TextInputCustom
|
||||||
|
placeholder="Masukkan username"
|
||||||
|
value={username}
|
||||||
|
onChangeText={(text) => setUsername(text)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ButtonCustom onPress={handleRegister}>Daftar</ButtonCustom>
|
||||||
|
{/* <Spacing />
|
||||||
<ButtonCustom
|
<ButtonCustom
|
||||||
title="Daftar"
|
title="Coba"
|
||||||
backgroundColor={MainColor.yellow}
|
backgroundColor={MainColor.yellow}
|
||||||
textColor={MainColor.black}
|
textColor={MainColor.black}
|
||||||
radius={10}
|
onPress={() => {
|
||||||
onPress={() => (
|
console.log("Home clicked");
|
||||||
console.log("Success register"),
|
router.push("/(application)/coba");
|
||||||
router.push("/(application)/home")
|
}}
|
||||||
)}
|
/> */}
|
||||||
/>
|
|
||||||
<Spacing />
|
|
||||||
{/* <ButtonCustom
|
|
||||||
title="Home"
|
|
||||||
backgroundColor={MainColor.yellow}
|
|
||||||
textColor={MainColor.black}
|
|
||||||
radius={10}
|
|
||||||
onPress={() => {
|
|
||||||
console.log("Home clicked");
|
|
||||||
router.push("/(application)/home");
|
|
||||||
}}
|
|
||||||
/> */}
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</ViewWrapper>
|
</ViewWrapper>
|
||||||
|
|||||||
@@ -2,22 +2,26 @@ import Spacing from "@/components/_ShareComponent/Spacing";
|
|||||||
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
||||||
import ButtonCustom from "@/components/Button/ButtonCustom";
|
import ButtonCustom from "@/components/Button/ButtonCustom";
|
||||||
import { MainColor } from "@/constants/color-palet";
|
import { MainColor } from "@/constants/color-palet";
|
||||||
import { Styles } from "@/styles/global-styles";
|
import { GStyles } from "@/styles/global-styles";
|
||||||
import { router } from "expo-router";
|
import { router } from "expo-router";
|
||||||
import { Text, View } from "react-native";
|
import { Text, View } from "react-native";
|
||||||
import { OtpInput } from "react-native-otp-entry";
|
import { OtpInput } from "react-native-otp-entry";
|
||||||
|
|
||||||
export default function VerificationView() {
|
export default function VerificationView() {
|
||||||
|
const handleVerification = () => {
|
||||||
|
console.log("Verification clicked");
|
||||||
|
router.push("/register");
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ViewWrapper withBackground>
|
<ViewWrapper withBackground>
|
||||||
<View style={Styles.authContainer}>
|
<View style={GStyles.authContainer}>
|
||||||
<View>
|
<View>
|
||||||
<View style={Styles.authContainerTitle}>
|
<View style={GStyles.authContainerTitle}>
|
||||||
<Text style={Styles.authTitle}>Verifikasi KOde OTP</Text>
|
<Text style={GStyles.authTitle}>Verifikasi KOde OTP</Text>
|
||||||
<Spacing height={30} />
|
<Spacing height={30} />
|
||||||
<Text style={Styles.textLabel}>Masukan 4 digit kode otp</Text>
|
<Text style={GStyles.textLabel}>Masukan 4 digit kode otp</Text>
|
||||||
<Text style={Styles.textLabel}>
|
<Text style={GStyles.textLabel}>
|
||||||
Yang di kirim ke +6282xxxxxxxxx
|
Yang di kirim ke +6282xxxxxxxxx
|
||||||
</Text>
|
</Text>
|
||||||
<Spacing height={30} />
|
<Spacing height={30} />
|
||||||
@@ -25,7 +29,7 @@ export default function VerificationView() {
|
|||||||
numberOfDigits={4}
|
numberOfDigits={4}
|
||||||
theme={{
|
theme={{
|
||||||
pinCodeContainerStyle: {
|
pinCodeContainerStyle: {
|
||||||
backgroundColor: MainColor.login,
|
backgroundColor: MainColor.text_input,
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderColor: MainColor.yellow,
|
borderColor: MainColor.yellow,
|
||||||
@@ -39,21 +43,21 @@ export default function VerificationView() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Spacing height={30} />
|
<Spacing height={30} />
|
||||||
<Text style={Styles.textLabel}>
|
<Text style={GStyles.textLabel}>
|
||||||
Tidak menerima kode ?{" "}
|
Tidak menerima kode ?{" "}
|
||||||
<Text style={Styles.textLabel}>Kirim Ulang</Text>
|
<Text style={GStyles.textLabel}>Kirim Ulang</Text>
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<Spacing height={30} />
|
<Spacing height={30} />
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<ButtonCustom
|
<ButtonCustom
|
||||||
title="Verifikasi"
|
|
||||||
backgroundColor={MainColor.yellow}
|
backgroundColor={MainColor.yellow}
|
||||||
textColor={MainColor.black}
|
textColor={MainColor.black}
|
||||||
radius={10}
|
onPress={() => handleVerification()}
|
||||||
onPress={() => router.push("/register")}
|
>
|
||||||
/>
|
Verifikasi
|
||||||
|
</ButtonCustom>
|
||||||
</View>
|
</View>
|
||||||
</ViewWrapper>
|
</ViewWrapper>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,120 +0,0 @@
|
|||||||
import Spacing from "@/components/_ShareComponent/Spacing";
|
|
||||||
import { Styles } from "@/styles/global-styles";
|
|
||||||
import { Ionicons } from "@expo/vector-icons";
|
|
||||||
import { Image } from "expo-image";
|
|
||||||
import { router } from "expo-router";
|
|
||||||
import { ScrollView, Text, TouchableOpacity, View } from "react-native";
|
|
||||||
import Icon from "react-native-vector-icons/FontAwesome";
|
|
||||||
import DynamicTruncatedText from "@/components/_ShareComponent/TruncatedText";
|
|
||||||
import { stylesHome } from "./homeViewStyle";
|
|
||||||
|
|
||||||
export default function HomeView() {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<ScrollView contentContainerStyle={{ flexGrow: 1 }}>
|
|
||||||
<View style={Styles.homeContainer}>
|
|
||||||
<Spacing height={20} />
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
backgroundColor: "#fff",
|
|
||||||
borderRadius: 10,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
source={require("@/assets/images/constants/home-hipmi.png")}
|
|
||||||
// placeholder={{ blurhash: "" }}
|
|
||||||
contentFit="cover"
|
|
||||||
transition={1000}
|
|
||||||
style={{
|
|
||||||
width: "100%",
|
|
||||||
height: 120,
|
|
||||||
borderRadius: 10,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<Spacing height={10} />
|
|
||||||
|
|
||||||
{/* Grid Section */}
|
|
||||||
<View style={stylesHome.gridContainer}>
|
|
||||||
<TouchableOpacity
|
|
||||||
style={stylesHome.gridItem}
|
|
||||||
onPress={() => router.push("/(application)/event")}
|
|
||||||
>
|
|
||||||
<Ionicons name="analytics" size={48} color="white" />
|
|
||||||
<Text style={stylesHome.gridLabel}>Event</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
<TouchableOpacity style={stylesHome.gridItem}>
|
|
||||||
<Ionicons name="share" size={48} color="white" />
|
|
||||||
<Text style={stylesHome.gridLabel}>Collaboration</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
<TouchableOpacity style={stylesHome.gridItem}>
|
|
||||||
<Ionicons name="cube" size={48} color="white" />
|
|
||||||
<Text style={stylesHome.gridLabel}>Voting</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
<TouchableOpacity style={stylesHome.gridItem}>
|
|
||||||
<Ionicons name="heart" size={48} color="white" />
|
|
||||||
<Text style={stylesHome.gridLabel}>Crowdfunding</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<Spacing height={10} />
|
|
||||||
|
|
||||||
{/* Job Vacancy Section */}
|
|
||||||
<View style={stylesHome.jobVacancyContainer}>
|
|
||||||
<View style={stylesHome.jobVacancyHeader}>
|
|
||||||
<Icon name="briefcase" size={24} color="white" />
|
|
||||||
<Text style={stylesHome.jobVacancyTitle}>Job Vacancy</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={stylesHome.vacancyList}>
|
|
||||||
{/* Vacancy Item 1 */}
|
|
||||||
<View style={stylesHome.vacancyItem}>
|
|
||||||
{/* <Icon name="user" size={20} color="#FFD700" /> */}
|
|
||||||
<View style={stylesHome.vacancyDetails}>
|
|
||||||
<DynamicTruncatedText
|
|
||||||
text="Bagas_banuna"
|
|
||||||
fontSize={14}
|
|
||||||
fontFamily="System"
|
|
||||||
style={stylesHome.vacancyName}
|
|
||||||
/>
|
|
||||||
<Spacing height={5} />
|
|
||||||
<DynamicTruncatedText
|
|
||||||
text="Dicari perawat kucing"
|
|
||||||
fontSize={12}
|
|
||||||
fontFamily="System"
|
|
||||||
style={stylesHome.vacancyDescription}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* Vacancy Item 2 */}
|
|
||||||
<View style={stylesHome.vacancyItem}>
|
|
||||||
{/* <Icon name="user" size={20} color="#FFD700" /> */}
|
|
||||||
<View style={stylesHome.vacancyDetails}>
|
|
||||||
<DynamicTruncatedText
|
|
||||||
text="fibramarcell"
|
|
||||||
fontSize={14}
|
|
||||||
fontFamily="System"
|
|
||||||
style={stylesHome.vacancyName}
|
|
||||||
/>
|
|
||||||
<Spacing height={5} />
|
|
||||||
<DynamicTruncatedText
|
|
||||||
text="Di Butuhkan Seorang..."
|
|
||||||
fontSize={12}
|
|
||||||
fontFamily="System"
|
|
||||||
style={stylesHome.vacancyDescription}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<Spacing height={20} />
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,194 +1,32 @@
|
|||||||
/* eslint-disable no-unused-expressions */
|
// import { ITabs } from "@/components/_Interface/types";
|
||||||
import Spacing from "@/components/_ShareComponent/Spacing";
|
import { StackCustom } from "@/components";
|
||||||
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
||||||
import { AccentColor, MainColor } from "@/constants/color-palet";
|
import { useNavigation } from "expo-router";
|
||||||
import { Ionicons } from "@expo/vector-icons";
|
import React, { useEffect } from "react";
|
||||||
import { Href, router } from "expo-router";
|
|
||||||
import React from "react";
|
|
||||||
import {
|
|
||||||
Dimensions,
|
|
||||||
StyleSheet,
|
|
||||||
Text,
|
|
||||||
TouchableOpacity,
|
|
||||||
View,
|
|
||||||
} from "react-native";
|
|
||||||
import Home_BottomFeatureSection from "./bottomFeatureSection";
|
import Home_BottomFeatureSection from "./bottomFeatureSection";
|
||||||
import Home_ImageSection from "./imageSection";
|
import Home_ImageSection from "./imageSection";
|
||||||
|
import TabSection from "./tabSection";
|
||||||
|
import { tabsHome } from "./tabsList";
|
||||||
import Home_FeatureSection from "./topFeatureSection";
|
import Home_FeatureSection from "./topFeatureSection";
|
||||||
|
|
||||||
interface Tabs {
|
export default function UiHome() {
|
||||||
id: string;
|
const navigation = useNavigation();
|
||||||
icon: string;
|
|
||||||
activeIcon: string;
|
|
||||||
label: string;
|
|
||||||
path: Href;
|
|
||||||
isActive: boolean;
|
|
||||||
disabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { width } = Dimensions.get("window");
|
useEffect(() => {
|
||||||
|
navigation.setOptions({});
|
||||||
export default function NewHomeView() {
|
}, [navigation]);
|
||||||
const tabs: Tabs[] = [
|
|
||||||
{
|
|
||||||
id: "forum",
|
|
||||||
icon: "chatbubble-ellipses-outline",
|
|
||||||
activeIcon: "chatbubble-ellipses",
|
|
||||||
label: "Forum",
|
|
||||||
path: "/forum",
|
|
||||||
isActive: true,
|
|
||||||
disabled: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "marketplace",
|
|
||||||
icon: "cart-outline",
|
|
||||||
activeIcon: "cart",
|
|
||||||
label: "Marketplace",
|
|
||||||
path: "/market-place",
|
|
||||||
isActive: false,
|
|
||||||
disabled: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "maps",
|
|
||||||
icon: "map-outline",
|
|
||||||
activeIcon: "map",
|
|
||||||
label: "Maps",
|
|
||||||
path: "/maps",
|
|
||||||
isActive: true,
|
|
||||||
disabled: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "profile",
|
|
||||||
icon: "person-outline",
|
|
||||||
activeIcon: "person",
|
|
||||||
label: "Profile",
|
|
||||||
path: "/profile",
|
|
||||||
isActive: true,
|
|
||||||
disabled: false,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const CustomTab = ({ icon, label, isActive, onPress, disabled }: any) => (
|
|
||||||
<TouchableOpacity
|
|
||||||
style={[styles.tabItem, isActive && styles.activeTab]}
|
|
||||||
onPress={onPress}
|
|
||||||
activeOpacity={0.7}
|
|
||||||
>
|
|
||||||
<View
|
|
||||||
style={[styles.iconContainer, isActive && styles.activeIconContainer]}
|
|
||||||
>
|
|
||||||
<Ionicons name={icon} size={20} color={isActive ? "#fff" : "#666"} />
|
|
||||||
</View>
|
|
||||||
<Text style={[styles.tabLabel, isActive && styles.activeTabLabel]}>
|
|
||||||
{label}
|
|
||||||
</Text>
|
|
||||||
{isActive && <View style={styles.activeIndicator} />}
|
|
||||||
</TouchableOpacity>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ViewWrapper
|
<ViewWrapper footerComponent={<TabSection tabs={tabsHome} />}>
|
||||||
tabBarComponent={
|
<StackCustom>
|
||||||
<View style={styles.tabBar}>
|
<Home_ImageSection />
|
||||||
<View style={styles.tabContainer}>
|
|
||||||
{tabs.map((e) => (
|
|
||||||
<CustomTab
|
|
||||||
key={e.id}
|
|
||||||
icon={e.icon}
|
|
||||||
label={e.label}
|
|
||||||
isActive={e.isActive}
|
|
||||||
onPress={() => {
|
|
||||||
e.disabled ? console.log("disabled") : router.push(e.path);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Home_ImageSection />
|
|
||||||
<Spacing height={10} />
|
|
||||||
|
|
||||||
{/* Grid Section */}
|
<Home_FeatureSection />
|
||||||
<Home_FeatureSection />
|
|
||||||
<Spacing height={10} />
|
|
||||||
|
|
||||||
{/* Job Vacancy Section */}
|
<Home_BottomFeatureSection />
|
||||||
<Home_BottomFeatureSection />
|
</StackCustom>
|
||||||
<Spacing height={20} />
|
|
||||||
</ViewWrapper>
|
</ViewWrapper>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
tabBar: {
|
|
||||||
backgroundColor: MainColor.darkblue,
|
|
||||||
borderTopColor: AccentColor.blue,
|
|
||||||
borderTopWidth: 1,
|
|
||||||
// borderTopEndRadius: 10,
|
|
||||||
// borderTopStartRadius: 10,
|
|
||||||
// tintColor: MainColor.yellow
|
|
||||||
// paddingBottom: 20,
|
|
||||||
// paddingTop: 10,
|
|
||||||
// shadowColor: AccentColor.blue,
|
|
||||||
// shadowOffset: {
|
|
||||||
// width: 0,
|
|
||||||
// height: -2,
|
|
||||||
// },
|
|
||||||
// shadowOpacity: 0.9,
|
|
||||||
// shadowRadius: 3,
|
|
||||||
// elevation: 5,
|
|
||||||
},
|
|
||||||
tabContainer: {
|
|
||||||
flexDirection: "row",
|
|
||||||
justifyContent: "space-around",
|
|
||||||
alignItems: "center",
|
|
||||||
paddingHorizontal: 0,
|
|
||||||
},
|
|
||||||
tabItem: {
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
paddingVertical: 8,
|
|
||||||
paddingHorizontal: 12,
|
|
||||||
minWidth: width / 5,
|
|
||||||
position: "relative",
|
|
||||||
},
|
|
||||||
activeTab: {
|
|
||||||
transform: [{ scale: 1.05 }],
|
|
||||||
},
|
|
||||||
iconContainer: {
|
|
||||||
padding: 8,
|
|
||||||
borderRadius: 20,
|
|
||||||
// marginBottom: 4,
|
|
||||||
},
|
|
||||||
activeIconContainer: {
|
|
||||||
// backgroundColor: "#007AFF",
|
|
||||||
// shadowColor: "#007AFF",
|
|
||||||
// shadowOffset: {
|
|
||||||
// width: 0,
|
|
||||||
// height: 2,
|
|
||||||
// },
|
|
||||||
// shadowOpacity: 0.3,
|
|
||||||
// shadowRadius: 4,
|
|
||||||
// elevation: 4,
|
|
||||||
},
|
|
||||||
tabLabel: {
|
|
||||||
fontSize: 10,
|
|
||||||
color: "#666",
|
|
||||||
fontWeight: "500",
|
|
||||||
},
|
|
||||||
activeTabLabel: {
|
|
||||||
color: MainColor.white,
|
|
||||||
fontWeight: "600",
|
|
||||||
},
|
|
||||||
activeIndicator: {
|
|
||||||
position: "absolute",
|
|
||||||
bottom: -2,
|
|
||||||
width: 4,
|
|
||||||
height: 4,
|
|
||||||
borderRadius: 2,
|
|
||||||
backgroundColor: "#007AFF",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
import { TextCustom } from "@/components";
|
||||||
import Spacing from "@/components/_ShareComponent/Spacing";
|
import Spacing from "@/components/_ShareComponent/Spacing";
|
||||||
import DynamicTruncatedText from "@/components/_ShareComponent/TruncatedText";
|
import React from "react";
|
||||||
import { Text, View } from "react-native";
|
import { View } from "react-native";
|
||||||
import Icon from "react-native-vector-icons/FontAwesome";
|
import Icon from "react-native-vector-icons/FontAwesome";
|
||||||
import { stylesHome } from "./homeViewStyle";
|
import { stylesHome } from "./homeViewStyle";
|
||||||
|
|
||||||
@@ -10,7 +11,10 @@ export default function Home_BottomFeatureSection() {
|
|||||||
<View style={stylesHome.jobVacancyContainer}>
|
<View style={stylesHome.jobVacancyContainer}>
|
||||||
<View style={stylesHome.jobVacancyHeader}>
|
<View style={stylesHome.jobVacancyHeader}>
|
||||||
<Icon name="briefcase" size={24} color="white" />
|
<Icon name="briefcase" size={24} color="white" />
|
||||||
<Text style={stylesHome.jobVacancyTitle}>Job Vacancy</Text>
|
<Spacing width={10}/>
|
||||||
|
<TextCustom bold size="large">
|
||||||
|
Job Vacancy
|
||||||
|
</TextCustom>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={stylesHome.vacancyList}>
|
<View style={stylesHome.vacancyList}>
|
||||||
@@ -18,19 +22,13 @@ export default function Home_BottomFeatureSection() {
|
|||||||
<View style={stylesHome.vacancyItem}>
|
<View style={stylesHome.vacancyItem}>
|
||||||
{/* <Icon name="user" size={20} color="#FFD700" /> */}
|
{/* <Icon name="user" size={20} color="#FFD700" /> */}
|
||||||
<View style={stylesHome.vacancyDetails}>
|
<View style={stylesHome.vacancyDetails}>
|
||||||
<DynamicTruncatedText
|
<TextCustom bold color="yellow" truncate size="large">
|
||||||
text="Bagas_banuna"
|
Bagas_banuna
|
||||||
fontSize={14}
|
</TextCustom>
|
||||||
fontFamily="System"
|
|
||||||
style={stylesHome.vacancyName}
|
|
||||||
/>
|
|
||||||
<Spacing height={5} />
|
<Spacing height={5} />
|
||||||
<DynamicTruncatedText
|
<TextCustom truncate={2}>
|
||||||
text="Dicari perawat kucing"
|
Dicari perawat kucing dan perawat anjing
|
||||||
fontSize={12}
|
</TextCustom>
|
||||||
fontFamily="System"
|
|
||||||
style={stylesHome.vacancyDescription}
|
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
@@ -38,19 +36,13 @@ export default function Home_BottomFeatureSection() {
|
|||||||
<View style={stylesHome.vacancyItem}>
|
<View style={stylesHome.vacancyItem}>
|
||||||
{/* <Icon name="user" size={20} color="#FFD700" /> */}
|
{/* <Icon name="user" size={20} color="#FFD700" /> */}
|
||||||
<View style={stylesHome.vacancyDetails}>
|
<View style={stylesHome.vacancyDetails}>
|
||||||
<DynamicTruncatedText
|
<TextCustom bold color="yellow" truncate size="large">
|
||||||
text="fibramarcell"
|
fibramarcell
|
||||||
fontSize={14}
|
</TextCustom>
|
||||||
fontFamily="System"
|
|
||||||
style={stylesHome.vacancyName}
|
|
||||||
/>
|
|
||||||
<Spacing height={5} />
|
<Spacing height={5} />
|
||||||
<DynamicTruncatedText
|
<TextCustom truncate={2}>
|
||||||
text="Di Butuhkan Seorang..."
|
Di Butuhkan Seorang Programer dan Designer
|
||||||
fontSize={12}
|
</TextCustom>
|
||||||
fontFamily="System"
|
|
||||||
style={stylesHome.vacancyDescription}
|
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
51
screens/Home/tabSection.tsx
Normal file
51
screens/Home/tabSection.tsx
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import { ICustomTab, ITabs } from "@/components/_Interface/types";
|
||||||
|
import { GStyles } from "@/styles/global-styles";
|
||||||
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
|
import { router } from "expo-router";
|
||||||
|
import React from "react";
|
||||||
|
import { Text, TouchableOpacity, View } from "react-native";
|
||||||
|
|
||||||
|
|
||||||
|
const CustomTab = ({ icon, label, isActive, onPress }: ICustomTab) => (
|
||||||
|
<TouchableOpacity
|
||||||
|
style={[GStyles.tabItem, isActive && GStyles.activeTab]}
|
||||||
|
onPress={onPress}
|
||||||
|
activeOpacity={0.7}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={[GStyles.iconContainer, isActive && GStyles.activeIconContainer]}
|
||||||
|
>
|
||||||
|
<Ionicons
|
||||||
|
name={icon as any}
|
||||||
|
size={20}
|
||||||
|
color={isActive ? "#fff" : "#666"}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<Text style={[GStyles.tabLabel, isActive && GStyles.activeTabLabel]}>
|
||||||
|
{label}
|
||||||
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default function TabSection({ tabs }: { tabs: ITabs[] }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<View style={GStyles.tabBar}>
|
||||||
|
<View style={GStyles.tabContainer}>
|
||||||
|
{tabs.map((e) => (
|
||||||
|
<CustomTab
|
||||||
|
key={e.id}
|
||||||
|
icon={e.icon}
|
||||||
|
label={e.label}
|
||||||
|
isActive={e.isActive}
|
||||||
|
onPress={() => {
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
e.disabled ? console.log("disabled") : router.push(e.path);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
40
screens/Home/tabsList.ts
Normal file
40
screens/Home/tabsList.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { ITabs } from "@/components/_Interface/types";
|
||||||
|
|
||||||
|
export const tabsHome: ITabs[] = [
|
||||||
|
{
|
||||||
|
id: "forum",
|
||||||
|
icon: "chatbubble-ellipses-outline",
|
||||||
|
activeIcon: "chatbubble-ellipses",
|
||||||
|
label: "Forum",
|
||||||
|
path: "/forum",
|
||||||
|
isActive: true,
|
||||||
|
disabled: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "marketplace",
|
||||||
|
icon: "cart-outline",
|
||||||
|
activeIcon: "cart",
|
||||||
|
label: "Marketplace",
|
||||||
|
path: "/marketplace",
|
||||||
|
isActive: false,
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "maps",
|
||||||
|
icon: "map-outline",
|
||||||
|
activeIcon: "map",
|
||||||
|
label: "Maps",
|
||||||
|
path: "/maps",
|
||||||
|
isActive: true,
|
||||||
|
disabled: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "profile",
|
||||||
|
icon: "person-outline",
|
||||||
|
activeIcon: "person",
|
||||||
|
label: "Profile",
|
||||||
|
path: "/profile/id-percoban-123456",
|
||||||
|
isActive: true,
|
||||||
|
disabled: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -9,7 +9,7 @@ export default function Home_FeatureSection() {
|
|||||||
<View style={stylesHome.gridContainer}>
|
<View style={stylesHome.gridContainer}>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={stylesHome.gridItem}
|
style={stylesHome.gridItem}
|
||||||
onPress={() => router.push("/(application)/event")}
|
onPress={() => router.push("/(application)/(user)/event/(tabs)")}
|
||||||
>
|
>
|
||||||
<Ionicons name="analytics" size={48} color="white" />
|
<Ionicons name="analytics" size={48} color="white" />
|
||||||
<Text style={stylesHome.gridLabel}>Event</Text>
|
<Text style={stylesHome.gridLabel}>Event</Text>
|
||||||
@@ -28,7 +28,7 @@ export default function Home_FeatureSection() {
|
|||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={stylesHome.gridContainer}>
|
{/* <View style={stylesHome.gridContainer}>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={stylesHome.gridItem}
|
style={stylesHome.gridItem}
|
||||||
onPress={() => router.push("/(application)/event")}
|
onPress={() => router.push("/(application)/event")}
|
||||||
@@ -48,7 +48,7 @@ export default function Home_FeatureSection() {
|
|||||||
<Ionicons name="heart" size={48} color="white" />
|
<Ionicons name="heart" size={48} color="white" />
|
||||||
<Text style={stylesHome.gridLabel}>Crowdfunding</Text>
|
<Text style={stylesHome.gridLabel}>Crowdfunding</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View> */}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
33
screens/Portofolio/ListPage.tsx
Normal file
33
screens/Portofolio/ListPage.tsx
Normal 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`,
|
||||||
|
},
|
||||||
|
];
|
||||||
28
screens/Portofolio/MenuDrawer.tsx
Normal file
28
screens/Portofolio/MenuDrawer.tsx
Normal 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}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
52
screens/Profile/AvatarAndBackground.tsx
Normal file
52
screens/Profile/AvatarAndBackground.tsx
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import { AvatarCustom } from "@/components";
|
||||||
|
import { AccentColor } from "@/constants/color-palet";
|
||||||
|
import DUMMY_IMAGE from "@/constants/dummy-image-value";
|
||||||
|
import { View, ImageBackground, StyleSheet } from "react-native";
|
||||||
|
|
||||||
|
const AvatarAndBackground = () => {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<ImageBackground
|
||||||
|
source={DUMMY_IMAGE.background}
|
||||||
|
style={styles.backgroundImage}
|
||||||
|
resizeMode="contain"
|
||||||
|
/>
|
||||||
|
{/* Background Image */}
|
||||||
|
|
||||||
|
{/* Avatar yang sedikit keluar */}
|
||||||
|
<View style={styles.avatarOverlap}>
|
||||||
|
<AvatarCustom
|
||||||
|
source={DUMMY_IMAGE.avatar}
|
||||||
|
size="lg"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AvatarAndBackground;
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
backgroundImage: {
|
||||||
|
width: "100%",
|
||||||
|
height: 150, // Tinggi background sesuai kebutuhan
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
borderRadius: 6,
|
||||||
|
overflow: "hidden",
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: AccentColor.blue,
|
||||||
|
backgroundColor: "white",
|
||||||
|
},
|
||||||
|
avatarOverlap: {
|
||||||
|
position: "absolute", // Meletakkan avatar di atas background
|
||||||
|
top: 90, // Posisi avatar sedikit keluar dari background
|
||||||
|
left: "50%", // Sentralisasi horizontal
|
||||||
|
transform: [{ translateX: -50 }], // Menggeser ke kiri 50% lebarnya
|
||||||
|
},
|
||||||
|
});
|
||||||
35
screens/Profile/ListPage.tsx
Normal file
35
screens/Profile/ListPage.tsx
Normal 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`,
|
||||||
|
},
|
||||||
|
];
|
||||||
35
screens/Profile/menuDrawerSection.tsx
Normal file
35
screens/Profile/menuDrawerSection.tsx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { IMenuDrawerItem } from "@/components/_Interface/types";
|
||||||
|
import MenuDrawerDynamicGrid from "@/components/Drawer/MenuDrawerDynamicGird";
|
||||||
|
import { router } from "expo-router";
|
||||||
|
|
||||||
|
export default function Profile_MenuDrawerSection({
|
||||||
|
drawerItems,
|
||||||
|
setShowLogoutAlert,
|
||||||
|
setIsDrawerOpen,
|
||||||
|
}: {
|
||||||
|
drawerItems: IMenuDrawerItem[];
|
||||||
|
setShowLogoutAlert: (value: boolean) => void;
|
||||||
|
setIsDrawerOpen: (value: boolean) => void;
|
||||||
|
}) {
|
||||||
|
const handlePress = (item: IMenuDrawerItem) => {
|
||||||
|
if (item.label === "Keluar") {
|
||||||
|
// console.log("Logout clicked");
|
||||||
|
setShowLogoutAlert(true);
|
||||||
|
} else {
|
||||||
|
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}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
129
screens/Profile/profilSection.tsx
Normal file
129
screens/Profile/profilSection.tsx
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
import { BaseBox, Grid, Spacing, TextCustom } from "@/components";
|
||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
|
||||||
|
import { FontAwesome5, Ionicons } from "@expo/vector-icons";
|
||||||
|
import { router, useLocalSearchParams } from "expo-router";
|
||||||
|
import { View } from "react-native";
|
||||||
|
import AvatarAndBackground from "./AvatarAndBackground";
|
||||||
|
|
||||||
|
export default function ProfilSection() {
|
||||||
|
const { id } = useLocalSearchParams();
|
||||||
|
|
||||||
|
const listData = [
|
||||||
|
{
|
||||||
|
icon: (
|
||||||
|
<Ionicons name="call-outline" size={ICON_SIZE_SMALL} color="white" />
|
||||||
|
),
|
||||||
|
label: "+6282340374412",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: (
|
||||||
|
<Ionicons name="mail-outline" size={ICON_SIZE_SMALL} color="white" />
|
||||||
|
),
|
||||||
|
label: "bagasbanuna@gmail.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: (
|
||||||
|
<Ionicons
|
||||||
|
name="location-outline"
|
||||||
|
size={ICON_SIZE_SMALL}
|
||||||
|
color="white"
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
label: "Jalan Raya Sesetan No. 123, Bandung, Indonesia",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: (
|
||||||
|
<FontAwesome5 name="transgender" size={ICON_SIZE_SMALL} color="white" />
|
||||||
|
),
|
||||||
|
label: "Laki-laki",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<BaseBox>
|
||||||
|
<AvatarAndBackground />
|
||||||
|
<Spacing height={50} />
|
||||||
|
|
||||||
|
<View style={{ alignItems: "center" }}>
|
||||||
|
<TextCustom bold size="large" align="center">
|
||||||
|
Nama User
|
||||||
|
</TextCustom>
|
||||||
|
<Spacing height={5} />
|
||||||
|
<TextCustom size="small">@Username</TextCustom>
|
||||||
|
</View>
|
||||||
|
<Spacing height={30} />
|
||||||
|
|
||||||
|
{listData.map((item, index) => (
|
||||||
|
<Grid key={index}>
|
||||||
|
<Grid.Col
|
||||||
|
span={2}
|
||||||
|
style={{
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item.icon}
|
||||||
|
</Grid.Col>
|
||||||
|
<Grid.Col span={10}>
|
||||||
|
<TextCustom bold>{item.label}</TextCustom>
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</BaseBox>
|
||||||
|
|
||||||
|
<BaseBox>
|
||||||
|
<View>
|
||||||
|
<TextCustom bold size="large" align="center">
|
||||||
|
Portofolio
|
||||||
|
</TextCustom>
|
||||||
|
<Spacing />
|
||||||
|
|
||||||
|
{Array.from({ length: 2 }).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>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<TextCustom
|
||||||
|
bold
|
||||||
|
align="right"
|
||||||
|
onPress={() => router.push(`/portofolio/${id}/list`)}
|
||||||
|
>
|
||||||
|
Lihat semua
|
||||||
|
</TextCustom>
|
||||||
|
</BaseBox>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,24 +1,49 @@
|
|||||||
import { StyleSheet } from "react-native";
|
import {
|
||||||
import { MainColor } from "../constants/color-palet";
|
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";
|
||||||
|
|
||||||
export const Styles = StyleSheet.create({
|
const { width } = Dimensions.get("window");
|
||||||
|
|
||||||
|
export const GStyles = StyleSheet.create({
|
||||||
|
// =============== Main Styles =============== //
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
paddingInline: 25,
|
paddingInline: 20,
|
||||||
paddingBlock: 10,
|
paddingBlock: 10,
|
||||||
backgroundColor: MainColor.darkblue,
|
backgroundColor: MainColor.darkblue,
|
||||||
},
|
},
|
||||||
containerWithBackground: {
|
containerWithBackground: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
paddingInline: 25,
|
paddingInline: 20,
|
||||||
paddingBlock: 10,
|
paddingBlock: 10,
|
||||||
},
|
},
|
||||||
imageBackground: {
|
imageBackground: {
|
||||||
height: "100%",
|
height: "100%",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
},
|
},
|
||||||
|
// Style saat disabled
|
||||||
// AUTHENTICATION
|
disabledBox: {
|
||||||
|
backgroundColor: MainColor.disabled,
|
||||||
|
borderColor: AccentColor.disabledBorder,
|
||||||
|
},
|
||||||
|
|
||||||
|
inputDisabled: {
|
||||||
|
backgroundColor: "#f0f0f0",
|
||||||
|
borderColor: "#ddd",
|
||||||
|
},
|
||||||
|
inputTextDisabled: {
|
||||||
|
color: "#777",
|
||||||
|
},
|
||||||
|
inputPlaceholderDisabled: {
|
||||||
|
color: "#444",
|
||||||
|
},
|
||||||
|
// =============== Main Styles =============== //
|
||||||
|
|
||||||
|
// =============== AUTHENTICATION =============== //
|
||||||
authContainer: {
|
authContainer: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
@@ -37,28 +62,227 @@ export const Styles = StyleSheet.create({
|
|||||||
color: MainColor.yellow,
|
color: MainColor.yellow,
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
},
|
},
|
||||||
|
// =============== AUTHENTICATION =============== //
|
||||||
// TEXT & LABEL
|
|
||||||
|
// =============== TEXT & LABEL =============== //
|
||||||
textLabel: {
|
textLabel: {
|
||||||
fontSize: 14,
|
fontSize: TEXT_SIZE_MEDIUM,
|
||||||
color: MainColor.white,
|
color: MainColor.white_gray,
|
||||||
fontWeight: "normal",
|
fontWeight: "normal",
|
||||||
},
|
},
|
||||||
|
// =============== TEXT & LABEL =============== //
|
||||||
|
|
||||||
// Stack Header Style
|
// =============== STACK HEADER =============== //
|
||||||
headerStyle: {
|
headerStyle: {
|
||||||
backgroundColor: MainColor.darkblue,
|
backgroundColor: AccentColor.darkblue,
|
||||||
},
|
},
|
||||||
headerTitleStyle: {
|
headerTitleStyle: {
|
||||||
color: MainColor.yellow,
|
color: MainColor.yellow,
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
|
fontSize: TEXT_SIZE_LARGE,
|
||||||
},
|
},
|
||||||
|
// =============== STACK HEADER =============== //
|
||||||
|
|
||||||
// HOME
|
// =============== HOME =============== //
|
||||||
homeContainer: {
|
homeContainer: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
paddingInline: 25,
|
paddingInline: 25,
|
||||||
paddingBlock: 10,
|
paddingBlock: 10,
|
||||||
backgroundColor: MainColor.darkblue,
|
backgroundColor: MainColor.darkblue,
|
||||||
},
|
},
|
||||||
|
// =============== HOME =============== //
|
||||||
|
|
||||||
|
// =============== TAB =============== //
|
||||||
|
tabBar: {
|
||||||
|
backgroundColor: MainColor.darkblue,
|
||||||
|
borderTopColor: AccentColor.blue,
|
||||||
|
borderTopWidth: 1,
|
||||||
|
// borderTopEndRadius: 10,
|
||||||
|
// borderTopStartRadius: 10,
|
||||||
|
// tintColor: MainColor.yellow
|
||||||
|
// paddingBottom: 20,
|
||||||
|
// paddingTop: 10,
|
||||||
|
// shadowColor: AccentColor.blue,
|
||||||
|
// shadowOffset: {
|
||||||
|
// width: 0,
|
||||||
|
// height: -2,
|
||||||
|
// },
|
||||||
|
// shadowOpacity: 0.9,
|
||||||
|
// shadowRadius: 3,
|
||||||
|
// elevation: 5,
|
||||||
|
},
|
||||||
|
tabContainer: {
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-around",
|
||||||
|
alignItems: "center",
|
||||||
|
paddingHorizontal: 0,
|
||||||
|
},
|
||||||
|
tabItem: {
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
paddingVertical: 8,
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
minWidth: width / 5,
|
||||||
|
position: "relative",
|
||||||
|
},
|
||||||
|
activeTab: {
|
||||||
|
transform: [{ scale: 1.05 }],
|
||||||
|
},
|
||||||
|
iconContainer: {
|
||||||
|
padding: 8,
|
||||||
|
borderRadius: 20,
|
||||||
|
// marginBottom: 4,
|
||||||
|
},
|
||||||
|
activeIconContainer: {
|
||||||
|
// backgroundColor: "#007AFF",
|
||||||
|
// shadowColor: "#007AFF",
|
||||||
|
// shadowOffset: {
|
||||||
|
// width: 0,
|
||||||
|
// height: 2,
|
||||||
|
// },
|
||||||
|
// shadowOpacity: 0.3,
|
||||||
|
// shadowRadius: 4,
|
||||||
|
// elevation: 4,
|
||||||
|
},
|
||||||
|
tabLabel: {
|
||||||
|
fontSize: 10,
|
||||||
|
color: "#666",
|
||||||
|
fontWeight: "500",
|
||||||
|
},
|
||||||
|
activeTabLabel: {
|
||||||
|
color: MainColor.white_gray,
|
||||||
|
fontWeight: "600",
|
||||||
|
},
|
||||||
|
activeIndicator: {
|
||||||
|
position: "absolute",
|
||||||
|
bottom: -2,
|
||||||
|
width: 4,
|
||||||
|
height: 4,
|
||||||
|
borderRadius: 2,
|
||||||
|
backgroundColor: "#007AFF",
|
||||||
|
},
|
||||||
|
// =============== TAB =============== //
|
||||||
|
|
||||||
|
// =============== BOTTOM BAR =============== //
|
||||||
|
bottomBar: {
|
||||||
|
backgroundColor: MainColor.darkblue,
|
||||||
|
borderTopColor: AccentColor.blue,
|
||||||
|
borderTopWidth: 1,
|
||||||
|
},
|
||||||
|
bottomBarContainer: {
|
||||||
|
paddingHorizontal: 15,
|
||||||
|
paddingVertical: 10,
|
||||||
|
},
|
||||||
|
// =============== 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 =============== //
|
||||||
});
|
});
|
||||||
|
|||||||
12
styles/header-styles.ts
Normal file
12
styles/header-styles.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { AccentColor } from "@/constants/color-palet";
|
||||||
|
import { NativeStackNavigationOptions } from "@react-navigation/native-stack";
|
||||||
|
import { GStyles } from "./global-styles";
|
||||||
|
|
||||||
|
export const HeaderStyles: NativeStackNavigationOptions = {
|
||||||
|
headerStyle: GStyles.headerStyle,
|
||||||
|
headerTitleStyle: GStyles.headerTitleStyle,
|
||||||
|
headerTitleAlign: "center",
|
||||||
|
contentStyle: {
|
||||||
|
borderBottomColor: AccentColor.blue,
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -13,5 +13,5 @@
|
|||||||
"**/*.tsx",
|
"**/*.tsx",
|
||||||
".expo/types/**/*.ts",
|
".expo/types/**/*.ts",
|
||||||
"expo-env.d.ts"
|
"expo-env.d.ts"
|
||||||
, "components/Button/ButtonCustom" ]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user