upd: redesign
Deskripsi: - login dan konfirmasi kode otp - firebase code env No Issues
This commit is contained in:
@@ -79,6 +79,12 @@ export default {
|
||||
URL_FIREBASE_DB: process.env.URL_FIREBASE_DB,
|
||||
PASS_ENC: process.env.PASS_ENC,
|
||||
WA_SERVER_TOKEN: process.env.WA_SERVER_TOKEN,
|
||||
FIREBASE_API_KEY: process.env.FIREBASE_API_KEY,
|
||||
FIREBASE_AUTH_DOMAIN: process.env.FIREBASE_AUTH_DOMAIN,
|
||||
FIREBASE_PROJECT_ID: process.env.FIREBASE_PROJECT_ID,
|
||||
FIREBASE_STORAGE_BUCKET: process.env.FIREBASE_STORAGE_BUCKET,
|
||||
FIREBASE_MESSAGING_SENDER_ID: process.env.FIREBASE_MESSAGING_SENDER_ID,
|
||||
FIREBASE_APP_ID: process.env.FIREBASE_APP_ID,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -20,10 +20,16 @@ export default function Index() {
|
||||
|
||||
const { signIn } = useAuthSession();
|
||||
const login = (): void => {
|
||||
const random: string = 'contohLoginMobileDarmasaba';
|
||||
var mytexttoEncryption = "contohLoginMobileDarmasaba"
|
||||
const encrypted = CryptoES.AES.encrypt(mytexttoEncryption, ConstEnv.pass_encrypt).toString();
|
||||
signIn(encrypted);
|
||||
// WARNING: This is a hardcoded bypass for development purposes.
|
||||
// It should be removed or secured before production release.
|
||||
if (__DEV__) {
|
||||
const random: string = 'contohLoginMobileDarmasaba';
|
||||
var mytexttoEncryption = "contohLoginMobileDarmasaba"
|
||||
const encrypted = CryptoES.AES.encrypt(mytexttoEncryption, ConstEnv.pass_encrypt).toString();
|
||||
signIn(encrypted);
|
||||
} else {
|
||||
console.warn("Bypass login disabled in production.");
|
||||
}
|
||||
}
|
||||
return (
|
||||
<View style={[Styles.wrapLogin, { backgroundColor: colors.background }]} >
|
||||
|
||||
BIN
assets/images/cogniti-dark.png
Normal file
BIN
assets/images/cogniti-dark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
BIN
assets/images/cogniti-light.png
Normal file
BIN
assets/images/cogniti-light.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
BIN
assets/images/logo-dark.png
Normal file
BIN
assets/images/logo-dark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 51 KiB |
@@ -53,11 +53,10 @@ export default function ViewLogin({ onValidate }: Props) {
|
||||
return (
|
||||
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
|
||||
<StatusBar style={theme === 'dark' ? 'light' : 'dark'} translucent={false} backgroundColor={colors.background} />
|
||||
<ToastCustom />
|
||||
<View style={[Styles.p20, Styles.h100]}>
|
||||
<View style={{ alignItems: "center", marginTop: 70, marginBottom: 50 }}>
|
||||
<Image
|
||||
source={require("../../assets/images/logo.png")}
|
||||
source={theme === 'dark' ? require("../../assets/images/logo-dark.png") : require("../../assets/images/logo.png")}
|
||||
style={[{ width: 300, height: 150 }]}
|
||||
width={270}
|
||||
height={110}
|
||||
@@ -71,18 +70,28 @@ export default function ViewLogin({ onValidate }: Props) {
|
||||
}}
|
||||
type="numeric"
|
||||
placeholder="XXX-XXX-XXXX"
|
||||
round
|
||||
itemLeft={<Text style={[Platform.OS === 'ios' && Styles.mt02]}>+62</Text>}
|
||||
info="Kami akan mengirim kode verifikasi melalui WhatsApp, guna mengonfirmasikan nomor Anda." />
|
||||
<ButtonForm
|
||||
text="MASUK"
|
||||
onPress={() => { handleCheckPhone() }}
|
||||
disabled={disableLogin}
|
||||
/>
|
||||
<View style={[{ width: '50%', alignSelf: 'center' }]}>
|
||||
<ButtonForm
|
||||
text="MASUK"
|
||||
onPress={() => { handleCheckPhone() }}
|
||||
disabled={disableLogin}
|
||||
/>
|
||||
</View>
|
||||
<View style={{ flex: 1 }} />
|
||||
<View style={{ alignItems: 'center' }}>
|
||||
<Image
|
||||
source={theme === 'dark' ? require("../../assets/images/cogniti-dark.png") : require("../../assets/images/cogniti-light.png")}
|
||||
style={{ width: 86, height: 27 }}
|
||||
resizeMode="contain"
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
{
|
||||
loadingLogin && <ModalLoading isVisible={true} setVisible={setLoadingLogin} />
|
||||
}
|
||||
<ToastCustom position="bottom" />
|
||||
</SafeAreaView>
|
||||
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useTheme } from "@/providers/ThemeProvider";
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
import { StatusBar } from "expo-status-bar";
|
||||
import { useState } from "react";
|
||||
import { Image, Platform, View } from "react-native";
|
||||
import { Image, SafeAreaView, View } from "react-native";
|
||||
import { OtpInput } from "react-native-otp-entry";
|
||||
import Toast from 'react-native-toast-message';
|
||||
import { ButtonForm } from "../buttonForm";
|
||||
@@ -58,13 +58,12 @@ export default function ViewVerification({ phone, otp }: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
|
||||
<StatusBar style={theme === 'dark' ? 'light' : 'dark'} translucent={false} backgroundColor={colors.background} />
|
||||
<ToastCustom />
|
||||
<View style={[Styles.wrapLogin, { backgroundColor: colors.background }]} >
|
||||
<View style={[Styles.p20, Styles.h100]} >
|
||||
<View style={{ alignItems: "center", marginTop: 70, marginBottom: 50 }}>
|
||||
<Image
|
||||
source={require("../../assets/images/logo.png")}
|
||||
source={theme === 'dark' ? require("../../assets/images/logo-dark.png") : require("../../assets/images/logo.png")}
|
||||
style={[{ width: 300, height: 150 }]}
|
||||
width={270}
|
||||
height={110}
|
||||
@@ -90,14 +89,25 @@ export default function ViewVerification({ phone, otp }: Props) {
|
||||
pinCodeTextStyle: { color: colors.text }
|
||||
}}
|
||||
/>
|
||||
<ButtonForm
|
||||
text="SUBMIT"
|
||||
onPress={() => { onCheckOtp() }}
|
||||
/>
|
||||
<Text style={[Styles.textInformation, Styles.mt05, Styles.cDefault, { textAlign: 'center', color: colors.tint }]}>
|
||||
Tidak Menerima kode verifikasi? <Text onPress={() => { resendOtp() }}>Kirim Ulang</Text>
|
||||
<View style={[{ width: '50%', alignSelf: 'center' }]}>
|
||||
<ButtonForm
|
||||
text="SUBMIT"
|
||||
onPress={() => { onCheckOtp() }}
|
||||
/>
|
||||
</View>
|
||||
<Text style={[Styles.textInformation, Styles.mt05, { textAlign: 'center', color: colors.dimmed }]}>
|
||||
Tidak Menerima kode verifikasi? <Text onPress={() => { resendOtp() }} style={[{ color: colors.tint }]}>Kirim Ulang</Text>
|
||||
</Text>
|
||||
<View style={{ flex: 1 }} />
|
||||
<View style={[{ alignItems: 'center' }]}>
|
||||
<Image
|
||||
source={theme === 'dark' ? require("../../assets/images/cogniti-dark.png") : require("../../assets/images/cogniti-light.png")}
|
||||
style={{ width: 86, height: 27 }}
|
||||
resizeMode="contain"
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
<ToastCustom position="bottom" />
|
||||
</SafeAreaView>
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ColorsStatus } from "@/constants/ColorsStatus";
|
||||
import Styles from "@/constants/Styles";
|
||||
import { useTheme } from "@/providers/ThemeProvider";
|
||||
import { TouchableOpacity } from "react-native";
|
||||
import Text from './Text';
|
||||
|
||||
@@ -10,8 +10,9 @@ type Props = {
|
||||
};
|
||||
|
||||
export function ButtonForm({ text, onPress, disabled }: Props) {
|
||||
const { colors } = useTheme();
|
||||
return (
|
||||
<TouchableOpacity style={[Styles.btnRound, { marginTop: 30,}, disabled && ColorsStatus.gray]} onPress={onPress} disabled={disabled}>
|
||||
<TouchableOpacity style={[Styles.btnRound, Styles.round05, Styles.mt30, { backgroundColor: colors.primary }, disabled && { backgroundColor: colors.tabIconDefault }]} onPress={onPress} disabled={disabled}>
|
||||
<Text style={[Styles.textDefaultSemiBold, Styles.cWhite]}>{text}</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
|
||||
@@ -74,7 +74,7 @@ export function InputForm({ label, value, placeholder, onChange, info, disable,
|
||||
/>
|
||||
</View>
|
||||
{error && (<Text style={[Styles.textInformation, { color: colors.error }, Styles.mt05]}>{errorText}</Text>)}
|
||||
{info != undefined && (<Text style={[Styles.textInformation, { color: colors.icon }, Styles.mt05]}>{info}</Text>)}
|
||||
{info != undefined && (<Text style={[Styles.textInformation, { color: colors.dimmed }, Styles.mt05]}>{info}</Text>)}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,12 +7,19 @@ import Text from "./Text";
|
||||
export default function ToastCustom({ position }: { position?: 'top' | 'bottom' }) {
|
||||
const { colors } = useTheme()
|
||||
return (
|
||||
<Toast autoHide onPress={() => Toast.hide()} visibilityTime={1500} position={position || 'bottom'} config={{
|
||||
small: ({ text1 }) => (
|
||||
<View style={[Styles.toastContainer, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
|
||||
<Text style={{ fontSize: 12 }}>{text1}</Text>
|
||||
</View>
|
||||
)
|
||||
}} />
|
||||
<Toast
|
||||
autoHide
|
||||
onPress={() => Toast.hide()}
|
||||
visibilityTime={1500}
|
||||
position={position || 'bottom'}
|
||||
bottomOffset={80}
|
||||
config={{
|
||||
small: ({ text1 }) => (
|
||||
<View style={[Styles.toastContainer, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
|
||||
<Text style={{ fontSize: 12 }}>{text1}</Text>
|
||||
</View>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -6,7 +6,7 @@ export const Colors = {
|
||||
text: '#11181C',
|
||||
background: '#f7f7f7ff',
|
||||
tint: tintColorLight,
|
||||
primary: '#19345E',
|
||||
primary: '#1F3C88',
|
||||
icon: '#1F3C88',
|
||||
card: '#ffffff',
|
||||
tabIconDefault: '#687076',
|
||||
@@ -24,7 +24,7 @@ export const Colors = {
|
||||
text: '#ECEDEE',
|
||||
background: '#0F1B2D',
|
||||
tint: tintColorDark,
|
||||
primary: '#19345E',
|
||||
primary: '#123A6F',
|
||||
icon: '#9DB9E8',
|
||||
card: '#16233A', // slightly lighter than background #151718
|
||||
tabIconDefault: '#9BA1A6',
|
||||
|
||||
@@ -2,5 +2,14 @@ import Constants from 'expo-constants';
|
||||
|
||||
export const ConstEnv = {
|
||||
url_storage: Constants?.expoConfig?.extra?.URL_STORAGE,
|
||||
pass_encrypt: Constants?.expoConfig?.extra?.PASS_ENC
|
||||
pass_encrypt: Constants?.expoConfig?.extra?.PASS_ENC,
|
||||
firebase: {
|
||||
apiKey: Constants?.expoConfig?.extra?.FIREBASE_API_KEY,
|
||||
authDomain: Constants?.expoConfig?.extra?.FIREBASE_AUTH_DOMAIN,
|
||||
projectId: Constants?.expoConfig?.extra?.FIREBASE_PROJECT_ID,
|
||||
storageBucket: Constants?.expoConfig?.extra?.FIREBASE_STORAGE_BUCKET,
|
||||
messagingSenderId: Constants?.expoConfig?.extra?.FIREBASE_MESSAGING_SENDER_ID,
|
||||
appId: Constants?.expoConfig?.extra?.FIREBASE_APP_ID,
|
||||
databaseURL: Constants?.expoConfig?.extra?.URL_FIREBASE_DB,
|
||||
}
|
||||
}
|
||||
@@ -88,6 +88,9 @@ const Styles = StyleSheet.create({
|
||||
mb15: {
|
||||
marginBottom: 15
|
||||
},
|
||||
mb20: {
|
||||
marginBottom: 20
|
||||
},
|
||||
mb30: {
|
||||
marginBottom: 30
|
||||
},
|
||||
@@ -130,6 +133,9 @@ const Styles = StyleSheet.create({
|
||||
mt15: {
|
||||
marginTop: 15
|
||||
},
|
||||
mt30: {
|
||||
marginTop: 30
|
||||
},
|
||||
mr05: {
|
||||
marginRight: 5
|
||||
},
|
||||
@@ -291,9 +297,9 @@ const Styles = StyleSheet.create({
|
||||
borderWidth: 1,
|
||||
},
|
||||
btnRound: {
|
||||
backgroundColor: '#19345E',
|
||||
backgroundColor: '#1F3C88',
|
||||
borderWidth: 0,
|
||||
borderColor: '#19345E',
|
||||
borderColor: '#1F3C88',
|
||||
alignItems: 'center',
|
||||
borderRadius: 30,
|
||||
marginTop: 15,
|
||||
@@ -309,7 +315,7 @@ const Styles = StyleSheet.create({
|
||||
},
|
||||
btnLainnya: {
|
||||
alignSelf: 'flex-start',
|
||||
backgroundColor: '#19345E',
|
||||
backgroundColor: '#1F3C88',
|
||||
paddingVertical: 5,
|
||||
marginVertical: 5
|
||||
},
|
||||
|
||||
61
lib/api.ts
61
lib/api.ts
@@ -96,30 +96,18 @@ export const apiGetGroup = async ({ user, active, search }: { user: string, acti
|
||||
};
|
||||
|
||||
export const apiCreateGroup = async (data: { user: string, name: string }) => {
|
||||
await api.post('mobile/group', data).then(response => {
|
||||
return response.data;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
const response = await api.post('mobile/group', data);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const apiEditGroup = async (data: { user: string, name: string }, id: string) => {
|
||||
await api.put(`mobile/group/${id}`, data).then(response => {
|
||||
return response.data;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
const response = await api.put(`mobile/group/${id}`, data);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const apiDeleteGroup = async (data: { user: string, isActive: boolean }, id: string) => {
|
||||
await api.delete(`mobile/group/${id}`, { data }).then(response => {
|
||||
return response.data;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
const response = await api.delete(`mobile/group/${id}`, { data });
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const apiGetPosition = async ({ user, active, search, group }: { user: string, active: string, search: string, group?: string }) => {
|
||||
@@ -128,22 +116,14 @@ export const apiGetPosition = async ({ user, active, search, group }: { user: st
|
||||
};
|
||||
|
||||
export const apiCreatePosition = async (data: { user: string, name: string, idGroup: string }) => {
|
||||
await api.post('mobile/position', data).then(response => {
|
||||
return response.data;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
const response = await api.post('mobile/position', data);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
|
||||
export const apiDeletePosition = async (data: { user: string, isActive: boolean }, id: string) => {
|
||||
await api.delete(`mobile/position/${id}`, { data }).then(response => {
|
||||
return response.data;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
const response = await api.delete(`mobile/position/${id}`, { data });
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const apiEditPosition = async (data: { user: string, name: string, idGroup: string }, id: string) => {
|
||||
@@ -207,12 +187,8 @@ export const apiUpdateDiscussionGeneralCommentar = async ({ id, data }: { id: st
|
||||
|
||||
|
||||
export const apiDeleteMemberDiscussionGeneral = async (data: { user: string, idUser: string }, id: string) => {
|
||||
await api.delete(`mobile/discussion-general/${id}/member`, { data }).then(response => {
|
||||
return response.data;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
const response = await api.delete(`mobile/discussion-general/${id}/member`, { data });
|
||||
return response.data;
|
||||
};
|
||||
|
||||
|
||||
@@ -222,19 +198,10 @@ export const apiUpdateStatusDiscussionGeneral = async ({ id, data }: { id: strin
|
||||
};
|
||||
|
||||
export const apiDeleteDiscussionGeneral = async (data: { user: string, active: boolean }, id: string) => {
|
||||
await api.delete(`mobile/discussion-general/${id}`, { data }).then(response => {
|
||||
return response.data;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
const response = await api.delete(`mobile/discussion-general/${id}`, { data });
|
||||
return response.data;
|
||||
};
|
||||
|
||||
// export const apiEditDiscussionGeneral = async (data: { user: string, title: string, desc: string }, id: string) => {
|
||||
// const response = await api.put(`/mobile/discussion-general/${id}`, data)
|
||||
// return response.data;
|
||||
// };
|
||||
|
||||
export const apiEditDiscussionGeneral = async (data: FormData, id: string) => {
|
||||
const response = await api.put(`/mobile/discussion-general/${id}`, data, {
|
||||
headers: {
|
||||
|
||||
@@ -23,6 +23,10 @@ export function pushToPage(category: string, idContent: string) {
|
||||
return router.push(`/member/${idContent}`)
|
||||
} else if (cat[0] == 'project') {
|
||||
return router.push(`/project/${idContent}`)
|
||||
} else if (cat[0] == 'group') {
|
||||
return router.push(`/group`)
|
||||
} else if (cat[0] == 'position') {
|
||||
return router.push(`/position`)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,23 +8,28 @@ import * as Notifications from 'expo-notifications';
|
||||
import { useEffect } from 'react';
|
||||
import { PermissionsAndroid, Platform } from 'react-native';
|
||||
|
||||
// Firebase config
|
||||
import { ConstEnv } from '@/constants/ConstEnv';
|
||||
|
||||
const RNfirebaseConfig = {
|
||||
apiKey: "AIzaSyB2hbsW91J3oRQx4_jgrCCNY0tNt5-21e8",
|
||||
authDomain: "googleapis.com",
|
||||
projectId: "mobile-darmasaba",
|
||||
storageBucket: "mobile-darmasaba.appspot.com",
|
||||
messagingSenderId: "867439221179",
|
||||
appId: "1:867439221179:android:4509f77478c8dce99b0c9e",
|
||||
databaseURL: "https://mobile-darmasaba-default-rtdb.asia-southeast1.firebasedatabase.app/"
|
||||
apiKey: ConstEnv.firebase.apiKey,
|
||||
authDomain: ConstEnv.firebase.authDomain,
|
||||
projectId: ConstEnv.firebase.projectId,
|
||||
storageBucket: ConstEnv.firebase.storageBucket,
|
||||
messagingSenderId: ConstEnv.firebase.messagingSenderId,
|
||||
appId: ConstEnv.firebase.appId,
|
||||
databaseURL: ConstEnv.firebase.databaseURL
|
||||
};
|
||||
|
||||
const initializeFirebase = async () => {
|
||||
try {
|
||||
const app = getApps().length ? getApp() : initializeApp(RNfirebaseConfig);
|
||||
let app;
|
||||
const apps = getApps();
|
||||
if (apps.length) {
|
||||
app = getApp() as any;
|
||||
} else {
|
||||
app = initializeApp(RNfirebaseConfig) as any;
|
||||
}
|
||||
const mess = getMessaging(app);
|
||||
// await registerDeviceForRemoteMessages(mess);
|
||||
// `registerDeviceForRemoteMessages` tidak perlu lagi
|
||||
await setAutoInitEnabled(mess, true);
|
||||
|
||||
return mess;
|
||||
|
||||
Reference in New Issue
Block a user