source: src/auth/context/firebase/auth-provider.tsx@ 5d6f37a

main
Last change on this file since 5d6f37a was 5d6f37a, checked in by Naum Shapkarovski <naumshapkarovski@…>, 7 weeks ago

add customer

  • Property mode set to 100644
File size: 5.0 KB
Line 
1'use client';
2
3import { useEffect, useReducer, useCallback, useMemo } from 'react';
4import {
5 signOut,
6 signInWithPopup,
7 onAuthStateChanged,
8 GoogleAuthProvider,
9 GithubAuthProvider,
10 TwitterAuthProvider,
11 sendEmailVerification,
12 sendPasswordResetEmail,
13 signInWithEmailAndPassword,
14 createUserWithEmailAndPassword,
15} from 'firebase/auth';
16import { collection, doc, getDoc, setDoc } from 'firebase/firestore';
17// firebase lib
18import { auth, db } from 'src/lib/firebase';
19import { collections } from 'src/lib/firestore';
20//
21import { AuthContext } from './auth-context';
22import { ActionMapType, AuthStateType, AuthUserType } from '../../types';
23
24// ----------------------------------------------------------------------
25
26// NOTE:
27// We only build demo at basic level.
28// Customer will need to do some extra handling yourself if you want to extend the logic and other features...
29
30// ----------------------------------------------------------------------
31
32enum Types {
33 INITIAL = 'INITIAL',
34}
35
36type Payload = {
37 [Types.INITIAL]: {
38 user: AuthUserType;
39 };
40};
41
42type Action = ActionMapType<Payload>[keyof ActionMapType<Payload>];
43
44const initialState: AuthStateType = {
45 user: null,
46 loading: true,
47};
48
49const reducer = (state: AuthStateType, action: Action) => {
50 if (action.type === Types.INITIAL) {
51 return {
52 loading: false,
53 user: action.payload.user,
54 };
55 }
56 return state;
57};
58
59// ----------------------------------------------------------------------
60
61type Props = {
62 children: React.ReactNode;
63};
64
65export function AuthProvider({ children }: Props) {
66 const [state, dispatch] = useReducer(reducer, initialState);
67
68 const initialize = useCallback(() => {
69 try {
70 onAuthStateChanged(auth, async (user) => {
71 if (user) {
72 if (user.emailVerified) {
73 const userProfile = doc(db, collections.administrator, user.uid);
74
75 const docSnap = await getDoc(userProfile);
76
77 const profile = docSnap.data();
78
79 dispatch({
80 type: Types.INITIAL,
81 payload: {
82 user: {
83 ...user,
84 ...profile,
85 id: user.uid,
86 },
87 },
88 });
89 } else {
90 dispatch({
91 type: Types.INITIAL,
92 payload: {
93 user: null,
94 },
95 });
96 }
97 } else {
98 dispatch({
99 type: Types.INITIAL,
100 payload: {
101 user: null,
102 },
103 });
104 }
105 });
106 } catch (error) {
107 console.error(error);
108 dispatch({
109 type: Types.INITIAL,
110 payload: {
111 user: null,
112 },
113 });
114 }
115 }, []);
116
117 useEffect(() => {
118 initialize();
119 }, [initialize]);
120
121 // LOGIN
122 const login = useCallback(async (email: string, password: string) => {
123 await signInWithEmailAndPassword(auth, email, password);
124 }, []);
125
126 const loginWithGoogle = useCallback(async () => {
127 const provider = new GoogleAuthProvider();
128
129 await signInWithPopup(auth, provider);
130 }, []);
131
132 const loginWithGithub = useCallback(async () => {
133 const provider = new GithubAuthProvider();
134
135 await signInWithPopup(auth, provider);
136 }, []);
137
138 const loginWithTwitter = useCallback(async () => {
139 const provider = new TwitterAuthProvider();
140
141 await signInWithPopup(auth, provider);
142 }, []);
143
144 // REGISTER
145 const register = useCallback(
146 async (email: string, password: string, firstName: string, lastName: string) => {
147 const newUser = await createUserWithEmailAndPassword(auth, email, password);
148
149 await sendEmailVerification(newUser.user);
150
151 const userProfile = doc(collection(db, collections.administrator), newUser.user?.uid);
152
153 await setDoc(userProfile, {
154 uid: newUser.user?.uid,
155 email,
156 displayName: `${firstName} ${lastName}`,
157 });
158 },
159 []
160 );
161
162 // LOGOUT
163 const logout = useCallback(async () => {
164 await signOut(auth);
165 }, []);
166
167 // FORGOT PASSWORD
168 const forgotPassword = useCallback(async (email: string) => {
169 await sendPasswordResetEmail(auth, email);
170 }, []);
171
172 // ----------------------------------------------------------------------
173
174 const checkAuthenticated = state.user?.emailVerified ? 'authenticated' : 'unauthenticated';
175
176 const status = state.loading ? 'loading' : checkAuthenticated;
177
178 const memoizedValue = useMemo(
179 () => ({
180 user: state.user,
181 method: 'firebase',
182 loading: status === 'loading',
183 authenticated: status === 'authenticated',
184 unauthenticated: status === 'unauthenticated',
185 //
186 login,
187 logout,
188 register,
189 forgotPassword,
190 loginWithGoogle,
191 loginWithGithub,
192 loginWithTwitter,
193 }),
194 [
195 status,
196 state.user,
197 //
198 login,
199 logout,
200 register,
201 forgotPassword,
202 loginWithGithub,
203 loginWithGoogle,
204 loginWithTwitter,
205 ]
206 );
207
208 return <AuthContext.Provider value={memoizedValue}>{children}</AuthContext.Provider>;
209}
Note: See TracBrowser for help on using the repository browser.