Compare commits
5 Commits
admin/14-a
...
auth/18-au
| Author | SHA1 | Date | |
|---|---|---|---|
| 1da4b00c2f | |||
| a4825343ba | |||
| 0b6c360500 | |||
| 6f5d04e73f | |||
| 4f4d9b2f05 |
2
.gitignore
vendored
@@ -38,3 +38,5 @@ yarn-error.*
|
||||
|
||||
app-example
|
||||
.qodo
|
||||
|
||||
.env
|
||||
|
||||
71
app.config.js
Normal file
@@ -0,0 +1,71 @@
|
||||
// app.config.js
|
||||
require('dotenv').config();
|
||||
|
||||
export default {
|
||||
name: 'HIPMI BADUNG',
|
||||
slug: 'hipmi-mobile',
|
||||
version: '1.0.0',
|
||||
orientation: 'portrait',
|
||||
icon: './assets/images/icon.png',
|
||||
scheme: 'hipmimobile',
|
||||
userInterfaceStyle: 'automatic',
|
||||
newArchEnabled: true,
|
||||
|
||||
ios: {
|
||||
supportsTablet: true,
|
||||
bundleIdentifier: 'com.anonymous.hipmi-mobile',
|
||||
infoPlist: {
|
||||
ITSAppUsesNonExemptEncryption: false,
|
||||
},
|
||||
},
|
||||
|
||||
android: {
|
||||
adaptiveIcon: {
|
||||
foregroundImage: './assets/images/splash-icon.png',
|
||||
backgroundColor: '#ffffff',
|
||||
},
|
||||
edgeToEdgeEnabled: true,
|
||||
package: 'com.bip.hipmimobileapp',
|
||||
},
|
||||
|
||||
web: {
|
||||
bundler: 'metro',
|
||||
output: 'static',
|
||||
favicon: './assets/images/favicon.png',
|
||||
},
|
||||
|
||||
plugins: [
|
||||
'expo-router',
|
||||
[
|
||||
'expo-splash-screen',
|
||||
{
|
||||
image: './assets/images/splash-icon.png',
|
||||
imageWidth: 200,
|
||||
resizeMode: 'contain',
|
||||
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: {
|
||||
typedRoutes: true,
|
||||
},
|
||||
|
||||
extra: {
|
||||
router: {},
|
||||
eas: {
|
||||
projectId: '5cf15964-4889-4755-b8ed-b99c61d614d1',
|
||||
},
|
||||
// Tambahkan environment variables ke sini
|
||||
API_BASE_URL: process.env.API_BASE_URL,
|
||||
},
|
||||
};
|
||||
@@ -17,7 +17,7 @@
|
||||
},
|
||||
"android": {
|
||||
"adaptiveIcon": {
|
||||
"foregroundImage": "./assets/images/adaptive-icon.png",
|
||||
"foregroundImage": "./assets/images/splash-icon.png",
|
||||
"backgroundColor": "#ffffff"
|
||||
},
|
||||
"edgeToEdgeEnabled": true,
|
||||
@@ -33,6 +33,14 @@ export default function UserLayout() {
|
||||
}}
|
||||
/>
|
||||
|
||||
<Stack.Screen
|
||||
name="waiting-room"
|
||||
options={{
|
||||
title: "Waiting Room",
|
||||
headerBackVisible: false,
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* ========== Profile Section ========= */}
|
||||
<Stack.Screen
|
||||
name="profile"
|
||||
|
||||
13
app/(application)/(user)/waiting-room.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import { InformationBox, ViewWrapper } from "@/components";
|
||||
|
||||
export default function WaitingRoom() {
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper>
|
||||
<InformationBox
|
||||
text="Permohonan akses Anda sedang dalam proses verifikasi oleh admin. Harap tunggu, Anda akan menerima pemberitahuan melalui Whatsapp setelah disetujui."
|
||||
/>
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { Stack } from "expo-router";
|
||||
import AppRoot from "@/screens/RootLayout/AppRoot";
|
||||
import "react-native-gesture-handler";
|
||||
import { SafeAreaProvider } from "react-native-safe-area-context";
|
||||
import Toast from "react-native-toast-message";
|
||||
@@ -8,28 +7,7 @@ export default function RootLayout() {
|
||||
return (
|
||||
<>
|
||||
<SafeAreaProvider>
|
||||
<Stack
|
||||
screenOptions={{
|
||||
headerStyle: { backgroundColor: MainColor.darkblue },
|
||||
headerTitleStyle: { color: MainColor.yellow, fontWeight: "bold" },
|
||||
headerTitleAlign: "center",
|
||||
}}
|
||||
>
|
||||
<Stack.Screen
|
||||
name="index"
|
||||
options={{ title: "", headerBackVisible: false }}
|
||||
/>
|
||||
<Stack.Screen name="+not-found" options={{ title: "" }} />
|
||||
<Stack.Screen
|
||||
name="verification"
|
||||
options={{ title: "", headerBackVisible: false }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="register"
|
||||
options={{ title: "", headerBackVisible: false }}
|
||||
/>
|
||||
<Stack.Screen name="(application)" options={{ headerShown: false }} />
|
||||
</Stack>
|
||||
<AppRoot />
|
||||
</SafeAreaProvider>
|
||||
<Toast />
|
||||
</>
|
||||
|
||||
BIN
assets/images/constants/logo-hipmi.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 60 KiB |
BIN
assets/images/splash-icon-back.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 51 KiB |
@@ -6,6 +6,7 @@ import { radiusMap } from "@/constants/radius-value";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { stylesButton } from "./buttonCustomStyles";
|
||||
import { Href, router } from "expo-router";
|
||||
import { ActivityIndicator } from "react-native-paper";
|
||||
|
||||
// Import radiusMap
|
||||
|
||||
@@ -23,6 +24,7 @@ interface ButtonProps {
|
||||
disabled?: boolean;
|
||||
iconLeft?: React.ReactNode;
|
||||
style?: StyleProp<ViewStyle>;
|
||||
isLoading?: boolean;
|
||||
}
|
||||
|
||||
const ButtonCustom: React.FC<ButtonProps> = ({
|
||||
@@ -36,6 +38,7 @@ const ButtonCustom: React.FC<ButtonProps> = ({
|
||||
disabled = false,
|
||||
iconLeft,
|
||||
style,
|
||||
isLoading = false,
|
||||
}) => {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
@@ -59,9 +62,13 @@ const ButtonCustom: React.FC<ButtonProps> = ({
|
||||
>
|
||||
{/* Render icon jika tersedia */}
|
||||
{iconLeft && iconLeft}
|
||||
{isLoading ? (
|
||||
<ActivityIndicator size={18} color={MainColor.darkblue} />
|
||||
) : (
|
||||
<Text style={[stylesButton.buttonText, { color: textColor }]}>
|
||||
{children || title}
|
||||
</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
23
lib/api.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
const API_BASE = (path: string) => {
|
||||
// const url = "https://stg-hipmi.wibudev.com/";
|
||||
const url = "http://172.20.173.254:3000/";
|
||||
return `${url}/${path}`;
|
||||
};
|
||||
|
||||
export async function apiVersion() {
|
||||
const response = await fetch(API_BASE("api/version"));
|
||||
const data = await response.json();
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function apiLoginBack({ nomor }: { nomor: string }) {
|
||||
const response = await fetch(API_BASE("api/auth/login"), {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ nomor: nomor }),
|
||||
});
|
||||
const data = await response.json();
|
||||
return data;
|
||||
}
|
||||
4796
package-lock.json
generated
@@ -20,6 +20,7 @@
|
||||
"@react-navigation/native-stack": "^7.3.21",
|
||||
"@types/lodash": "^4.17.20",
|
||||
"@types/react-native-vector-icons": "^6.4.18",
|
||||
"axios": "^1.11.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"expo": "53.0.17",
|
||||
"expo-blur": "~14.1.5",
|
||||
@@ -44,6 +45,7 @@
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0",
|
||||
"react-native": "0.79.5",
|
||||
"react-native-dotenv": "^3.4.11",
|
||||
"react-native-gesture-handler": "~2.24.0",
|
||||
"react-native-international-phone-number": "^0.9.3",
|
||||
"react-native-maps": "1.20.1",
|
||||
@@ -65,6 +67,7 @@
|
||||
"@types/react": "~19.0.10",
|
||||
"eslint": "^9.25.0",
|
||||
"eslint-config-expo": "~9.2.0",
|
||||
"expo-module-scripts": "^4.1.10",
|
||||
"typescript": "~5.8.3"
|
||||
},
|
||||
"private": true
|
||||
|
||||
@@ -2,15 +2,28 @@ 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 { apiLogin, apiVersion } from "@/service/api";
|
||||
import { GStyles } from "@/styles/global-styles";
|
||||
import { router } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Text, View } from "react-native";
|
||||
import PhoneInput, { ICountry } from "react-native-international-phone-number";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function LoginView() {
|
||||
const [version, setVersion] = useState<string>("");
|
||||
const [selectedCountry, setSelectedCountry] = useState<null | ICountry>(null);
|
||||
const [inputValue, setInputValue] = useState<string>("");
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
onLoadVersion();
|
||||
}, []);
|
||||
|
||||
async function onLoadVersion() {
|
||||
const res = await apiVersion();
|
||||
setVersion(res.data);
|
||||
}
|
||||
|
||||
function handleInputValue(phoneNumber: string) {
|
||||
setInputValue(phoneNumber);
|
||||
@@ -20,19 +33,59 @@ export default function LoginView() {
|
||||
setSelectedCountry(country);
|
||||
}
|
||||
|
||||
function handleLogin() {
|
||||
async function validateData() {
|
||||
if (inputValue.length === 0) {
|
||||
return Toast.show({
|
||||
type: "error",
|
||||
text1: "Masukan nomor anda",
|
||||
});
|
||||
}
|
||||
|
||||
if (selectedCountry === null) {
|
||||
return Toast.show({
|
||||
type: "error",
|
||||
text1: "Pilih negara",
|
||||
});
|
||||
}
|
||||
|
||||
if (inputValue.length < 9) {
|
||||
return Toast.show({
|
||||
type: "error",
|
||||
text1: "Nomor tidak valid",
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async function handleLogin() {
|
||||
const isValid = await validateData();
|
||||
if (!isValid) return;
|
||||
|
||||
const callingCode = selectedCountry?.callingCode.replace(/^\+/, "") || "";
|
||||
const fixNumber = callingCode + inputValue;
|
||||
// console.log("fixNumber", fixNumber);
|
||||
const fixNumber = inputValue.replace(/\s+/g, "");
|
||||
const realNumber = callingCode + fixNumber;
|
||||
|
||||
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);
|
||||
setLoading(true);
|
||||
const response = await apiLogin({ nomor: realNumber });
|
||||
|
||||
router.navigate("/verification");
|
||||
if (response.success) {
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Sukses",
|
||||
text2: "Kode OTP berhasil dikirim",
|
||||
});
|
||||
router.navigate(`/verification?kodeId=${response.kodeId}`);
|
||||
setLoading(false);
|
||||
// router.replace("/(application)/coba");
|
||||
// router.navigate("/admin/dashboard")
|
||||
} else {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Error",
|
||||
text2: response.message,
|
||||
});
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -49,15 +102,15 @@ export default function LoginView() {
|
||||
<Text
|
||||
style={{
|
||||
position: "absolute",
|
||||
bottom: 30,
|
||||
right: 20,
|
||||
bottom: 35,
|
||||
right: 50,
|
||||
fontSize: 10,
|
||||
fontWeight: "thin",
|
||||
fontStyle: "italic",
|
||||
color: MainColor.white_gray,
|
||||
}}
|
||||
>
|
||||
powered by muku.id
|
||||
{version} | powered by muku.id
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
@@ -72,8 +125,9 @@ export default function LoginView() {
|
||||
|
||||
<Spacing />
|
||||
|
||||
<ButtonCustom onPress={handleLogin}>Login</ButtonCustom>
|
||||
|
||||
<ButtonCustom onPress={handleLogin} isLoading={loading}>
|
||||
Login
|
||||
</ButtonCustom>
|
||||
<Spacing />
|
||||
|
||||
{/* <ButtonCustom onPress={() => router.navigate("/admin/investment")}>
|
||||
|
||||
@@ -5,16 +5,71 @@ import TextInputCustom from "@/components/TextInput/TextInputCustom";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { GStyles } from "@/styles/global-styles";
|
||||
import { MaterialCommunityIcons } from "@expo/vector-icons";
|
||||
import { router } from "expo-router";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { Text, View } from "react-native";
|
||||
import { useState } from "react";
|
||||
import { apiRegister } from "@/service/api";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function RegisterView() {
|
||||
const [username, setUsername] = useState("Bagas Banuna");
|
||||
const handleRegister = () => {
|
||||
console.log("Success register", username);
|
||||
router.push("/(application)/(user)/home");
|
||||
const { nomor } = useLocalSearchParams();
|
||||
const [username, setUsername] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const validasiData = () => {
|
||||
if (!nomor) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Gagal",
|
||||
text2: "Nomor tidak ditemukan",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (!username) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Gagal",
|
||||
text2: "Username tidak boleh kosong",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
async function handleRegister() {
|
||||
const isValid = validasiData();
|
||||
if (!isValid) return;
|
||||
const data = {
|
||||
nomor: nomor as string,
|
||||
username: username,
|
||||
};
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await apiRegister({ data });
|
||||
console.log("Success register", JSON.stringify(response, null, 2));
|
||||
|
||||
if (response.success) {
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Sukses",
|
||||
text2: "Anda berhasil terdaftar",
|
||||
});
|
||||
router.replace("/(application)/(user)/waiting-room");
|
||||
}
|
||||
|
||||
Toast.show({
|
||||
type: "info",
|
||||
text1: "Info",
|
||||
text2: response.message,
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.log("Error register", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper withBackground>
|
||||
@@ -33,7 +88,7 @@ export default function RegisterView() {
|
||||
<Text style={GStyles.textLabel}>
|
||||
Anda akan terdaftar dengan nomor
|
||||
</Text>
|
||||
<Text style={GStyles.textLabel}>+6282xxxxxxxxx</Text>
|
||||
<Text style={GStyles.textLabel}>+{nomor}</Text>
|
||||
<Spacing />
|
||||
</View>
|
||||
<TextInputCustom
|
||||
@@ -42,17 +97,9 @@ export default function RegisterView() {
|
||||
onChangeText={(text) => setUsername(text)}
|
||||
/>
|
||||
|
||||
<ButtonCustom onPress={handleRegister}>Daftar</ButtonCustom>
|
||||
{/* <Spacing />
|
||||
<ButtonCustom
|
||||
title="Coba"
|
||||
backgroundColor={MainColor.yellow}
|
||||
textColor={MainColor.black}
|
||||
onPress={() => {
|
||||
console.log("Home clicked");
|
||||
router.push("/(application)/coba");
|
||||
}}
|
||||
/> */}
|
||||
<ButtonCustom isLoading={loading} onPress={handleRegister}>
|
||||
Daftar
|
||||
</ButtonCustom>
|
||||
</View>
|
||||
</View>
|
||||
</ViewWrapper>
|
||||
|
||||
@@ -2,16 +2,74 @@ import Spacing from "@/components/_ShareComponent/Spacing";
|
||||
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
||||
import ButtonCustom from "@/components/Button/ButtonCustom";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { apiCheckCodeOtp, apiValidationCode } from "@/service/api";
|
||||
import { GStyles } from "@/styles/global-styles";
|
||||
import { router } from "expo-router";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Text, View } from "react-native";
|
||||
import { OtpInput } from "react-native-otp-entry";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function VerificationView() {
|
||||
const handleVerification = () => {
|
||||
console.log("Verification clicked");
|
||||
router.push("/register");
|
||||
const { kodeId } = useLocalSearchParams();
|
||||
const [codeOtp, setCodeOtp] = useState<string>("");
|
||||
const [inputOtp, setInputOtp] = useState<string>("");
|
||||
const [nomor, setNomor] = useState<string>("");
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
onLoadCheckCodeOtp(kodeId as string);
|
||||
}, [kodeId]);
|
||||
|
||||
async function onLoadCheckCodeOtp(kodeId: string) {
|
||||
const response = await apiCheckCodeOtp({ kodeId: kodeId });
|
||||
console.log("response ", JSON.stringify(response, null, 2));
|
||||
setCodeOtp(response.otp);
|
||||
setNomor(response.nomor);
|
||||
}
|
||||
|
||||
const handleVerification = async () => {
|
||||
const codeOtpNumber = parseInt(codeOtp);
|
||||
const inputOtpNumber = parseInt(inputOtp);
|
||||
|
||||
console.log("codeOtpNumber ", codeOtpNumber, typeof codeOtpNumber);
|
||||
console.log("inputOtpNumber ", inputOtpNumber, typeof inputOtpNumber);
|
||||
|
||||
if (inputOtpNumber !== codeOtpNumber) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Gagal",
|
||||
text2: "Kode OTP tidak sesuai",
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await apiValidationCode({ nomor: nomor });
|
||||
console.log("response ", JSON.stringify(response, null, 2));
|
||||
|
||||
if (response.success) {
|
||||
if (response.active) {
|
||||
if (response.roleId === "1") {
|
||||
router.replace("/(application)/(user)/home");
|
||||
} else {
|
||||
router.replace("/(application)/admin/dashboard");
|
||||
}
|
||||
} else {
|
||||
router.replace("/(application)/(user)/waiting-room");
|
||||
}
|
||||
} else {
|
||||
router.replace(`/register?nomor=${nomor}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("Error verification", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper withBackground>
|
||||
@@ -21,11 +79,10 @@ export default function VerificationView() {
|
||||
<Text style={GStyles.authTitle}>Verifikasi KOde OTP</Text>
|
||||
<Spacing height={30} />
|
||||
<Text style={GStyles.textLabel}>Masukan 4 digit kode otp</Text>
|
||||
<Text style={GStyles.textLabel}>
|
||||
Yang di kirim ke +6282xxxxxxxxx
|
||||
</Text>
|
||||
<Text style={GStyles.textLabel}>Yang di kirim ke +{nomor}</Text>
|
||||
<Spacing height={30} />
|
||||
<OtpInput
|
||||
disabled={codeOtp === ""}
|
||||
numberOfDigits={4}
|
||||
theme={{
|
||||
pinCodeContainerStyle: {
|
||||
@@ -41,6 +98,7 @@ export default function VerificationView() {
|
||||
paddingRight: 10,
|
||||
},
|
||||
}}
|
||||
onTextChange={(otp: string) => setInputOtp(otp)}
|
||||
/>
|
||||
<Spacing height={30} />
|
||||
<Text style={GStyles.textLabel}>
|
||||
@@ -52,6 +110,8 @@ export default function VerificationView() {
|
||||
</View>
|
||||
|
||||
<ButtonCustom
|
||||
isLoading={loading}
|
||||
disabled={codeOtp === ""}
|
||||
backgroundColor={MainColor.yellow}
|
||||
textColor={MainColor.black}
|
||||
onPress={() => handleVerification()}
|
||||
|
||||
31
screens/RootLayout/AppRoot.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { Stack } from "expo-router";
|
||||
|
||||
export default function AppRoot() {
|
||||
return (
|
||||
<>
|
||||
<Stack
|
||||
screenOptions={{
|
||||
headerStyle: { backgroundColor: MainColor.darkblue },
|
||||
headerTitleStyle: { color: MainColor.yellow, fontWeight: "bold" },
|
||||
headerTitleAlign: "center",
|
||||
}}
|
||||
>
|
||||
<Stack.Screen
|
||||
name="index"
|
||||
options={{ title: "", headerBackVisible: false }}
|
||||
/>
|
||||
<Stack.Screen name="+not-found" options={{ title: "" }} />
|
||||
<Stack.Screen
|
||||
name="verification"
|
||||
options={{ title: "", headerBackVisible: false }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="register"
|
||||
options={{ title: "", headerBackVisible: false }}
|
||||
/>
|
||||
<Stack.Screen name="(application)" options={{ headerShown: false }} />
|
||||
</Stack>
|
||||
</>
|
||||
);
|
||||
}
|
||||
48
service/api.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import axios, { AxiosInstance } from "axios";
|
||||
import Constants from "expo-constants";
|
||||
|
||||
const API_BASE_URL = Constants.expoConfig?.extra?.API_BASE_URL;
|
||||
|
||||
const api: AxiosInstance = axios.create({
|
||||
baseURL: API_BASE_URL,
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
export async function apiVersion() {
|
||||
console.log("API_BASE_URL", API_BASE_URL);
|
||||
const response = await api.get("/version");
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function apiLogin({ nomor }: { nomor: string }) {
|
||||
const response = await api.post("/auth/login", {
|
||||
nomor: nomor,
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function apiCheckCodeOtp({ kodeId }: { kodeId: string }) {
|
||||
const response = await api.get(`/auth/check/${kodeId}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function apiValidationCode({ nomor }: { nomor: string }) {
|
||||
const response = await api.post(`/auth/validasi`, {
|
||||
nomor: nomor,
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function apiRegister({
|
||||
data,
|
||||
}: {
|
||||
data: { nomor: string; username: string };
|
||||
}) {
|
||||
const response = await api.post(`/auth/register`, {
|
||||
data: data,
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
@@ -11,6 +11,8 @@
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"app/(application)/admin/app-information/business-field/[id]"
|
||||
"app/(application)/admin/app-information/business-field/[id]",
|
||||
".expo/types/**/*.ts",
|
||||
"expo-env.d.ts"
|
||||
]
|
||||
}
|
||||
|
||||