Skip to content

Commit

Permalink
feat: login & register
Browse files Browse the repository at this point in the history
  • Loading branch information
dimaslesmana committed Dec 1, 2021
1 parent 102d1c9 commit a47f616
Show file tree
Hide file tree
Showing 11 changed files with 6,178 additions and 4,029 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

# misc
.DS_Store
.env
.env.local
.env.development.local
.env.test.local
Expand Down
9,866 changes: 5,858 additions & 4,008 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 1 addition & 5 deletions src/config/firebase.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { getApp, getApps, initializeApp } from 'firebase/app';

const firebaseConfig = {
apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
Expand All @@ -10,6 +8,4 @@ const firebaseConfig = {
appId: process.env.REACT_APP_FIREBASE_APP_ID,
};

export const firebaseApp = getApps().length
? getApp()
: initializeApp(firebaseConfig);
export default firebaseConfig;
53 changes: 53 additions & 0 deletions src/contexts/auth/AuthProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { useState, useEffect } from 'react';
import { UserData } from 'types/userData';
import { AuthContext } from './auth.context';
import { firebaseAuth, registerUser, loginUser } from 'services/firebase';

export const AuthProvider: React.FC = ({ children }) => {
const [currentUser, setCurrentUser] = useState<UserData | null>(null);

useEffect(() => {
const unsubscribe = firebaseAuth.onAuthStateChanged((user: any) => {
setCurrentUser(user);
console.log("onAuthStateChanged", currentUser);
});

return unsubscribe;
}, []);

const register = async (email: string, password: string, fullName: string, phoneNumber: string, address: string, gender: 'male' | 'female') => {
try {
await registerUser(email, password, fullName, phoneNumber, address, gender);
} catch (error) {
console.error(error);
throw new Error("Oops! Something went wrong.");
}
};

const login = async (email: string, password: string) => {
try {
const result = await loginUser(email, password);

if (!result.status && result.message === 'email_not_verified') {
throw new Error("email_not_verified");
}
} catch (error) {
console.error(error);

if (error instanceof Error) {
if (error.message === 'email_not_verified') {
throw new Error("email_not_verified");
}
return;
}

throw new Error("Oops! Something went wrong.");
}
};

return (
<AuthContext.Provider value={{ currentUser, register, login }}>
{children}
</AuthContext.Provider>
);
};
14 changes: 14 additions & 0 deletions src/contexts/auth/auth.context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { createContext } from 'react';
import { UserData } from 'types/userData';

interface Context {
currentUser: UserData | null;
register: (email: string, password: string, fullName: string, phoneNumber: string, address: string, gender: 'male' | 'female') => void;
login: (email: string, password: string) => void;
}

export const AuthContext = createContext<Context>({
currentUser: null,
register: () => {},
login: () => {},
});
2 changes: 2 additions & 0 deletions src/contexts/auth/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './AuthProvider';
export * from './auth.context';
13 changes: 8 additions & 5 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import App from './App';
import * as serviceWorkerRegistration from './serviceWorkerRegistration';
import reportWebVitals from './reportWebVitals';
import { LoadScript } from '@react-google-maps/api';
import { AuthProvider } from 'contexts/auth';
import { PersonalContactProvider } from 'contexts/personalContact';
import { EmergencyServiceProvider } from 'contexts/emergencyService';

Expand All @@ -12,11 +13,13 @@ const googleMapsApiKey = `${process.env.REACT_APP_GOOGLE_MAPS_API_KEY}`;
ReactDOM.render(
<React.StrictMode>
<LoadScript googleMapsApiKey={googleMapsApiKey} libraries={['places']}>
<EmergencyServiceProvider>
<PersonalContactProvider>
<App />
</PersonalContactProvider>
</EmergencyServiceProvider>
<AuthProvider>
<EmergencyServiceProvider>
<PersonalContactProvider>
<App />
</PersonalContactProvider>
</EmergencyServiceProvider>
</AuthProvider>
</LoadScript>
</React.StrictMode>,
document.getElementById('root')
Expand Down
59 changes: 55 additions & 4 deletions src/pages/auth/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import React, { useRef, useState, useContext } from 'react';
import { useHistory } from 'react-router-dom';
import {
IonButton,
IonCard,
Expand All @@ -16,11 +18,59 @@ import {
import { klikDarurat } from 'assets';
import { mailOutline, lockClosedOutline } from 'ionicons/icons';

import { AuthContext } from '../../contexts/auth';

import Layout from 'components/layout';

const Login: React.FC = () => {
const handleLoginClick = () => {
console.log('Login button clicked!');
const [toastMessage, setToastMessage] = useState<string>("");
const [loading, setLoading] = useState<boolean>(false);
const emailRef = useRef<HTMLIonInputElement>(null);
const passwordRef = useRef<HTMLIonInputElement>(null);
const authCtx = useContext(AuthContext);
const history = useHistory();

const handleLoginClick = async () => {
const email = emailRef.current?.value;
const password = passwordRef.current?.value;

if (!email || !password) {
return;
}

if (email.toString().trim().length === 0) {
setToastMessage("Email wajib diisi");
return;
}

if (password.toString().length === 0) {
setToastMessage("Kata sandi wajib diisi");
return;
}

try {
setToastMessage("");
setLoading(true);

await authCtx.login(email.toString(), password.toString());

//setLoading(false);
history.length > 0 ? history.goBack() : history.replace('/main');

} catch (error) {
if (error instanceof Error) {
if (error.message === 'email_not_verified') {
setLoading(false);
setToastMessage("Harap verifikasi email anda");
console.log("Harap verifikasi email anda");
}
return;
} else {
setToastMessage("Gagal untuk login");
}
}

setLoading(false);
};

return (
Expand Down Expand Up @@ -86,15 +136,15 @@ const Login: React.FC = () => {
color="primary"
slot="start"
/>
<IonInput type="email" placeholder="Email" />
<IonInput type="email" inputMode="email" placeholder="Email" ref={emailRef} required />
</IonItem>
<IonItem style={{ '--background': 'inherit' }}>
<IonIcon
icon={lockClosedOutline}
color="primary"
slot="start"
/>
<IonInput type="password" placeholder="Kata Sandi" />
<IonInput type="password" placeholder="Kata Sandi" ref={passwordRef} required />
</IonItem>
</IonList>
</IonCol>
Expand All @@ -107,6 +157,7 @@ const Login: React.FC = () => {
expand="block"
shape="round"
onClick={handleLoginClick}
disabled={loading}
>
Masuk
</IonButton>
Expand Down
131 changes: 124 additions & 7 deletions src/pages/auth/Register.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import React, { useRef, useState, useContext } from 'react';
import { useHistory } from 'react-router-dom';
import {
IonButton,
IonCard,
Expand All @@ -11,16 +13,103 @@ import {
IonList,
IonRouterLink,
IonRow,
IonSelect,
IonSelectOption,
IonText,
} from '@ionic/react';
import { klikDarurat } from 'assets';
import { personOutline, mailOutline, lockClosedOutline } from 'ionicons/icons';
import { personOutline, mailOutline, lockClosedOutline, callOutline, transgenderOutline, homeOutline } from 'ionicons/icons';

import { AuthContext } from '../../contexts/auth';

import Layout from 'components/layout';

const Register: React.FC = () => {
const handleRegisterClick = () => {
console.log('Register button clicked!');
const [toastMessage, setToastMessage] = useState<string>("");
const [loading, setLoading] = useState<boolean>(false);
const [selectedGender, setSelectedGender] = useState<'male' | 'female'>();
const fullNameRef = useRef<HTMLIonInputElement>(null);
const emailRef = useRef<HTMLIonInputElement>(null);
const phoneNumberRef = useRef<HTMLIonInputElement>(null);
const addressRef = useRef<HTMLIonInputElement>(null);
const passwordRef = useRef<HTMLIonInputElement>(null);
const confirmPasswordRef = useRef<HTMLIonInputElement>(null);
const authCtx = useContext(AuthContext);
const history = useHistory();

const handleSelectGender = (event: CustomEvent) => {
const gender = event.detail.value;

setSelectedGender(gender);
};

const handleRegisterClick = async () => {
const fullName = fullNameRef.current?.value;
const email = emailRef.current?.value;
const phoneNumber = phoneNumberRef.current?.value;
const address = addressRef.current?.value;
const password = passwordRef.current?.value;
const confirmPassword = confirmPasswordRef.current?.value;

if (!fullName || !email || !phoneNumber || !address || !selectedGender || !password || !confirmPassword) {
return;
}

if (fullName.toString().trim().length === 0) {
setToastMessage("Nama wajib diisi");
return;
}

if (email.toString().trim().length === 0) {
setToastMessage("Email wajib diisi");
return;
}

if (phoneNumber.toString().trim().length === 0) {
setToastMessage("Nomor telepon wajib diisi");
return;
}

if (address.toString().trim().length === 0) {
setToastMessage("Alamat wajib diisi");
return;
}

if (password.toString().length === 0) {
setToastMessage("Kata sandi wajib diisi");
return;
}

if (password.toString().length < 6) {
setToastMessage("Kata sandi minimal 6 karakter");
return;
}

if (password.toString() !== confirmPassword.toString()) {
setToastMessage("Kata sandi tidak sesuai");
return;
}

try {
setToastMessage("");
setLoading(true);

await authCtx.register(
email.toString(),
password.toString(),
fullName.toString().trim(),
phoneNumber.toString().trim(),
address.toString().trim(),
selectedGender
);

setLoading(false);
history.length > 0 ? history.goBack() : history.replace('/login');
} catch (error) {
setToastMessage("Gagal membuat akun");
}

setLoading(false);
};

return (
Expand Down Expand Up @@ -86,31 +175,58 @@ const Register: React.FC = () => {
color="secondary"
slot="start"
/>
<IonInput placeholder="Nama Lengkap" />
<IonInput type="text" inputMode="text" ref={fullNameRef} placeholder="Nama Lengkap" required />
</IonItem>
<IonItem>
<IonIcon
icon={mailOutline}
color="secondary"
slot="start"
/>
<IonInput placeholder="Email" />
<IonInput type="email" inputMode="email" ref={emailRef} placeholder="Email" required />
</IonItem>
<IonItem>
<IonIcon
icon={callOutline}
color="secondary"
slot="start"
/>
<IonInput type="tel" inputMode="tel" ref={phoneNumberRef} placeholder="Nomor Telepon" required />
</IonItem>
<IonItem>
<IonIcon
icon={homeOutline}
color="secondary"
slot="start"
/>
<IonInput type="text" inputMode="text" ref={addressRef} placeholder="Alamat" required />
</IonItem>
<IonItem>
<IonIcon
icon={transgenderOutline}
color="secondary"
slot="start"
/>
<IonSelect placeholder="Jenis Kelamin" onIonChange={handleSelectGender} interface="alert">
<IonSelectOption value="male">Laki-laki</IonSelectOption>
<IonSelectOption value="female">Perempuan</IonSelectOption>
</IonSelect>
</IonItem>
<IonItem>
<IonIcon
icon={lockClosedOutline}
color="secondary"
slot="start"
/>
<IonInput placeholder="Kata Sandi" />
<IonInput type="password" ref={passwordRef} placeholder="Kata Sandi" required />
</IonItem>
<IonItem>
<IonIcon
icon={lockClosedOutline}
color="secondary"
slot="start"
/>
<IonInput placeholder="Ulangi Kata Sandi" />
<IonInput type="password" ref={confirmPasswordRef} placeholder="Ulangi Kata Sandi" required />
</IonItem>
</IonList>
</IonCol>
Expand All @@ -123,6 +239,7 @@ const Register: React.FC = () => {
expand="block"
shape="round"
onClick={handleRegisterClick}
disabled={loading}
>
Daftar
</IonButton>
Expand Down
Loading

0 comments on commit a47f616

Please sign in to comment.