Skip to content

Commit

Permalink
Merge pull request #85 from AndyOooh/ED1-70-fix-notifications
Browse files Browse the repository at this point in the history
Ed1 70 fix notifications
  • Loading branch information
AndyOooh authored Mar 31, 2024
2 parents b30b856 + d8f734b commit 97892d9
Show file tree
Hide file tree
Showing 27 changed files with 157 additions and 165 deletions.
3 changes: 2 additions & 1 deletion apps/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@
"yup": "1.3.2"
},
"devDependencies": {
"@hookform/devtools": "^4.3.1",
"eslint-config-custom": "*",
"event-dee-types": "*",
"@hookform/devtools": "^4.3.1",
"tsconfig": "*"
}
}
17 changes: 14 additions & 3 deletions apps/app/src/app/(protected)/events/create/form/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
'use client';

import React, { useContext, useEffect } from 'react';
import { addDoc, arrayUnion, collection, doc, increment, updateDoc } from 'firebase/firestore';
import {
DocumentData,
addDoc,
arrayUnion,
collection,
doc,
increment,
serverTimestamp,
updateDoc,
} from 'firebase/firestore';
import { DevTool } from '@hookform/devtools';
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
Expand All @@ -14,6 +23,7 @@ import { EventInfo } from './event-info';
import { IcreateEventSchema, createEventSchema } from './validation';
import { EventLocation } from './event-location';
import { EventRoles } from './event-roles';
import { FetchDocByIdParams } from 'event-dee-types';

export const CreateEventForm = () => {
const { currentUser } = useContext(CurrUserContext);
Expand Down Expand Up @@ -41,8 +51,8 @@ export const CreateEventForm = () => {
* Fetch metaData/events doc to get currentId for events.
* Perhaps this can be done using const eventsDocRef = doc(db, 'metaData', 'events') ??
*/
const fetchDocById = getCloudFunction('fetchDocById');
const { data: eventsMetadata }: any = await fetchDocById({
const fetchDocById = getCloudFunction<FetchDocByIdParams, DocumentData>('fetchDocById');
const eventsMetadata = await fetchDocById({
collectionName: 'metaData',
id: 'events',
});
Expand All @@ -51,6 +61,7 @@ export const CreateEventForm = () => {
...data,
event_id: eventsMetadata.currentId + 1,
creatorUid: currentUser.uid,
createdAt: serverTimestamp(),
});

// Step 2: Get the reference to the newly created event
Expand Down
11 changes: 9 additions & 2 deletions apps/app/src/app/(protected)/events/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,19 @@ import { getCloudFunction } from '__firebase/clientApp';
import { Events as EventComp } from './components/Events';
import { CreateEventButton } from './components/create-event-button';
import { cache } from 'react';
import { FetchDocsWithQueryParams } from 'event-dee-types';

export const revalidate = 3600; // revalidate the data at most every hour

const getEvents = cache(async () => {
const fetchDocsWithQuery = getCloudFunction('fetchDocsWithQuery');
const { data } = await fetchDocsWithQuery({ collectionName: 'events' });
const fetchDocsWithQuery = getCloudFunction<FetchDocsWithQueryParams>('fetchDocsWithQuery');
const data = await fetchDocsWithQuery({
collectionName: 'events',
orderBy: {
field: 'createdAt',
direction: 'desc',
},
});
return data;
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ export const personalInfoSchema = ({ initialEmail }) =>
// const exists = await checkEmailExists(email);
// return !exists;
// return !(await checkEmailExists(value));
const checkEmailExists = getCloudFunction('checkEmailExists'); // Our custom function
const emailExists = (await checkEmailExists(value)).data;
const checkEmailExists = getCloudFunction<string, boolean>('checkEmailExists');
const emailExists = await checkEmailExists(value);
return !emailExists;
}),
invite_link: yup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,15 @@ export const Step1 = () => {
const provider = watch('provider');

const onSubmit = async (data: any) => {
const checkEmailExists = getCloudFunction('checkEmailExists');
const emailExists = (await checkEmailExists(data.email)).data;
const checkEmailExists = getCloudFunction<string, boolean>('checkEmailExists');
const emailExists = await checkEmailExists(data.email);
if (emailExists) {
setError('email', { message: 'Email already exists' });
return;
}

await createUserWithEmailAndPassword(data.email, data.new_password);

setWFormData(prev => ({
...prev,
...data,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { DEFAULT_PROFILE_PHOTO_URL } from '__utils/global-consts';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import { LoaderSpinner } from '__components/ui/LoaderSpinner';
import { CustomClaims, SetCustomClaimsParams } from 'event-dee-types';

export const Step2 = () => {
const [, setWFormData] = useRecoilState(wizardForm);
Expand All @@ -38,7 +39,7 @@ export const Step2 = () => {
setLoading(true);
const { first_name, last_name, company_name, company_type } = data;

const customClaims = {
const customClaims: CustomClaims = {
basic_info_done: true,
type: 'business',
};
Expand All @@ -60,10 +61,14 @@ export const Step2 = () => {
const userDocRef = doc(db, 'users', authUser?.uid);
await updateDoc(userDocRef, userDocUpdates);

const setCustomClaims = getCloudFunction('setCustomClaims'); // Our custom function
const setCustomClaims = getCloudFunction<SetCustomClaimsParams, Promise<{ message: string }>>(
'setCustomClaims'
);
await setCustomClaims({
uid: authUser?.uid,
payload: customClaims,
data: {
uid: authUser?.uid,
payload: customClaims,
},
});

if (!authUser?.photoURL) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ export const Step1 = () => {
const provider = watch('provider');

const onSubmit = async (data: any) => {
const checkEmailExists = getCloudFunction('checkEmailExists');
const emailExists = (await checkEmailExists(data.email)).data;
const checkEmailExists = getCloudFunction<string, boolean>('checkEmailExists');
const emailExists = await checkEmailExists(data.email);
if (emailExists) {
setError('email', { message: 'Email already exists' });
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { ImageUpload } from '__components/ImageUpload';
import { LoaderSpinner } from '__components/ui/LoaderSpinner';
import { DEFAULT_PROFILE_PHOTO_URL } from '__utils/global-consts';
import { ActionButton } from 'ui';
import { SetCustomClaimsParams } from 'event-dee-types';

export const Step3 = () => {
const [authUser] = useAuthState(auth);
Expand Down Expand Up @@ -69,10 +70,14 @@ export const Step3 = () => {

await updateDoc(userDocRef, userDocUpdates);

const setCustomClaims = getCloudFunction('setCustomClaims'); // Our custom function
const setCustomClaims = getCloudFunction<SetCustomClaimsParams, { message: string }>(
'setCustomClaims'
);
await setCustomClaims({
uid: authUser?.uid,
payload: customClaims,
data: {
uid: authUser?.uid,
payload: customClaims,
},
});

setWFormData(prev => ({
Expand Down
37 changes: 27 additions & 10 deletions apps/app/src/firebase/clientApp.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import { initializeApp, getApp, getApps, FirebaseOptions } from 'firebase/app';
import {
browserLocalPersistence,
browserPopupRedirectResolver,
browserSessionPersistence,
// browserLocalPersistence,
// browserPopupRedirectResolver,
// browserSessionPersistence,
// indexedDBLocalPersistence,
// initializeAuth,
connectAuthEmulator,
getAuth,
indexedDBLocalPersistence,
initializeAuth,
} from 'firebase/auth';
import { connectFirestoreEmulator, getFirestore } from 'firebase/firestore';
import { DocumentData, connectFirestoreEmulator, getFirestore } from 'firebase/firestore';
import { connectStorageEmulator, getStorage } from 'firebase/storage';
import { connectFunctionsEmulator, getFunctions, httpsCallable } from 'firebase/functions';
import {
connectFunctionsEmulator,
getFunctions,
httpsCallable,
HttpsCallable,
} from 'firebase/functions';

/*
* Do NOT use window object or other browser specific objects here
Expand All @@ -36,9 +41,21 @@ const auth = getAuth(app);
// popupRedirectResolver: browserPopupRedirectResolver,
// });
const functions = getFunctions();
const getCloudFunction = (functionName: string) => {
const returnedFunction = httpsCallable(functions, functionName);
return returnedFunction;

/* OLD */
// const getCloudFunction = (functionName: string) => {
// const returnedFunction = httpsCallable(functions, functionName);
// return returnedFunction;
// };
const getCloudFunction = <Params, Result = DocumentData[] | DocumentData>(
functionName: string
): ((params: Params) => Promise<Result>) => {
const callable: HttpsCallable<Params, Result> = httpsCallable(functions, functionName);

return async (params: Params) => {
const result = await callable(params);
return result.data;
};
};

if (process.env.NEXT_PUBLIC_EMULATORS_ON === 'true' && process.env.NODE_ENV === 'development') {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,75 +1,2 @@
{
"kind": "identitytoolkit#DownloadAccountResponse",
"users": [
{
"localId": "DI4Dx3YiiDonUcaz0UiiFjdCUkAU",
"createdAt": "1704033339723",
"lastLoginAt": "1707153741167",
"displayName": "Orange Chicken",
"photoUrl": "http://localhost:9199/v0/b/event-dee-staging.appspot.com/o/users%2FDI4Dx3YiiDonUcaz0UiiFjdCUkAU%2Fimages%2Fprofile?alt=media&token=aaa55962-ac74-4b1d-8045-7c688f925cc4",
"customAttributes": "{\"basic_info_done\":true,\"type\":\"freelancer\"}",
"providerUserInfo": [
{
"providerId": "google.com",
"rawId": "6233296176568572704053954672800598602635",
"federatedId": "6233296176568572704053954672800598602635",
"displayName": "Orange Chicken",
"email": "[email protected]",
"screenName": "chicken_orange"
}
],
"validSince": "1707153003",
"email": "[email protected]",
"emailVerified": true,
"disabled": false,
"lastRefreshAt": "2024-02-05T17:26:05.063Z"
},
{
"localId": "XobXVTMfKX21NwEP7V5LEuuX4q8u",
"createdAt": "1704023132744",
"lastLoginAt": "1704023132744",
"photoUrl": "http://localhost:9199/v0/b/event-dee-staging.appspot.com/o/users%2FXobXVTMfKX21NwEP7V5LEuuX4q8u%2Fimages%2Fprofile?alt=media&token=be3f3bef-d833-4dd0-b275-11a58ec238a3",
"passwordHash": "fakeHash:salt=fakeSaltUu0sqgKGXdW18M52lrCJ:password=oooooo",
"salt": "fakeSaltUu0sqgKGXdW18M52lrCJ",
"passwordUpdatedAt": 1707153003743,
"customAttributes": "{\"basic_info_done\":true,\"type\":\"freelancer\"}",
"providerUserInfo": [
{
"providerId": "password",
"email": "[email protected]",
"federatedId": "[email protected]",
"rawId": "[email protected]",
"photoUrl": "http://localhost:9199/v0/b/event-dee-staging.appspot.com/o/users%2FXobXVTMfKX21NwEP7V5LEuuX4q8u%2Fimages%2Fprofile?alt=media&token=be3f3bef-d833-4dd0-b275-11a58ec238a3"
}
],
"validSince": "1707153003",
"email": "[email protected]",
"emailVerified": false,
"disabled": false
},
{
"localId": "qIsokoD9bxhWt2tcFdcNpAg0DPZb",
"createdAt": "1704107208217",
"lastLoginAt": "1707153085233",
"photoUrl": "https://storage.cloud.google.com/event-dee-staging.appspot.com/misc/profile-photo-placeholder.jpg",
"passwordHash": "fakeHash:salt=fakeSalth89eFQSxrdhCytX68Nxe:password=bbbbbb",
"salt": "fakeSalth89eFQSxrdhCytX68Nxe",
"passwordUpdatedAt": 1707153003743,
"customAttributes": "{\"basic_info_done\":true,\"type\":\"business\"}",
"providerUserInfo": [
{
"providerId": "password",
"email": "[email protected]",
"federatedId": "[email protected]",
"rawId": "[email protected]",
"photoUrl": "https://storage.cloud.google.com/event-dee-staging.appspot.com/misc/profile-photo-placeholder.jpg"
}
],
"validSince": "1707153003",
"email": "[email protected]",
"emailVerified": false,
"disabled": false,
"lastRefreshAt": "2024-02-05T17:16:54.279Z"
}
]
}
{"kind":"identitytoolkit#DownloadAccountResponse","users":[{"localId":"DI4Dx3YiiDonUcaz0UiiFjdCUkAU","createdAt":"1704033339723","lastLoginAt":"1707153741167","displayName":"Orange Chicken","photoUrl":"http://localhost:9199/v0/b/event-dee-staging.appspot.com/o/users%2FDI4Dx3YiiDonUcaz0UiiFjdCUkAU%2Fimages%2Fprofile?alt=media&token=aaa55962-ac74-4b1d-8045-7c688f925cc4","customAttributes":"{\"basic_info_done\":true,\"type\":\"freelancer\"}","providerUserInfo":[{"providerId":"google.com","rawId":"6233296176568572704053954672800598602635","federatedId":"6233296176568572704053954672800598602635","displayName":"Orange Chicken","email":"[email protected]","screenName":"chicken_orange"}],"validSince":"1711872929","email":"[email protected]","emailVerified":true,"disabled":false},{"localId":"XobXVTMfKX21NwEP7V5LEuuX4q8u","createdAt":"1704023132744","lastLoginAt":"1704023132744","photoUrl":"http://localhost:9199/v0/b/event-dee-staging.appspot.com/o/users%2FXobXVTMfKX21NwEP7V5LEuuX4q8u%2Fimages%2Fprofile?alt=media&token=be3f3bef-d833-4dd0-b275-11a58ec238a3","passwordHash":"fakeHash:salt=fakeSaltUu0sqgKGXdW18M52lrCJ:password=oooooo","salt":"fakeSaltUu0sqgKGXdW18M52lrCJ","passwordUpdatedAt":1711872929949,"customAttributes":"{\"basic_info_done\":true,\"type\":\"freelancer\"}","providerUserInfo":[{"providerId":"password","email":"[email protected]","federatedId":"[email protected]","rawId":"[email protected]","photoUrl":"http://localhost:9199/v0/b/event-dee-staging.appspot.com/o/users%2FXobXVTMfKX21NwEP7V5LEuuX4q8u%2Fimages%2Fprofile?alt=media&token=be3f3bef-d833-4dd0-b275-11a58ec238a3"}],"validSince":"1711872929","email":"[email protected]","emailVerified":false,"disabled":false},{"localId":"qIsokoD9bxhWt2tcFdcNpAg0DPZb","createdAt":"1704107208217","lastLoginAt":"1711872965495","photoUrl":"https://storage.cloud.google.com/event-dee-staging.appspot.com/misc/profile-photo-placeholder.jpg","passwordHash":"fakeHash:salt=fakeSalth89eFQSxrdhCytX68Nxe:password=bbbbbb","salt":"fakeSalth89eFQSxrdhCytX68Nxe","passwordUpdatedAt":1711872929949,"customAttributes":"{\"basic_info_done\":true,\"type\":\"business\"}","providerUserInfo":[{"providerId":"password","email":"[email protected]","federatedId":"[email protected]","rawId":"[email protected]","photoUrl":"https://storage.cloud.google.com/event-dee-staging.appspot.com/misc/profile-photo-placeholder.jpg"}],"validSince":"1711872929","email":"[email protected]","emailVerified":false,"disabled":false,"lastRefreshAt":"2024-03-31T08:35:24.874Z"}]}

Binary file not shown.
Binary file not shown.
Binary file not shown.
1 change: 1 addition & 0 deletions apps/firebase-cloud-functions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"firebase-functions": "^4.2.0"
},
"devDependencies": {
"event-dee-types": "*",
"firebase-functions-test": "^3.0.0",
"typescript": "^4.9.0"
},
Expand Down
39 changes: 21 additions & 18 deletions apps/firebase-cloud-functions/src/auth/callable.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import { getAuth } from 'firebase-admin/auth';
import { SetCustomClaimsParams } from 'event-dee-types';

/*
* Callable
* Checks if email exists in auth
*/
export const checkEmailExists = functions.https.onCall(async email => {
export const checkEmailExists = functions.https.onCall(async (email: string): Promise<boolean> => {
try {
console.log('checkEmailExists called!');
const userRecord = await admin.auth().getUserByEmail(email);
console.log('πŸš€ file: index.ts:40 userRecord:', userRecord);
return { emailExists: true };
return true;
} catch (error) {
console.log('πŸš€ file: index.ts:44 error:', error);
return false;
Expand All @@ -23,21 +24,23 @@ export const checkEmailExists = functions.https.onCall(async email => {
* Callable
* Sets custom claims on auth user
*/
export const setCustomClaims = functions.https.onCall(async (data, context) => {
try {
const { uid, payload } = data;
await getAuth().setCustomUserClaims(uid, payload);
// /* Lookup the user associated with the specified uid. */
// const userNew = await getAuth()
// .getUser(uid)
// .then(userRecord => {
// // The claims can be accessed on the user record.
// console.log(userRecord?.customClaims);
// });
// console.log('πŸš€ file: crud-user.ts:85 userNew:', userNew);
export const setCustomClaims = functions.https.onCall(
async ({ data, context }: SetCustomClaimsParams): Promise<{ message: string }> => {
try {
const { uid, payload } = data;
await getAuth().setCustomUserClaims(uid, payload);
// /* Lookup the user associated with the specified uid. */
// const userNew = await getAuth()
// .getUser(uid)
// .then(userRecord => {
// // The claims can be accessed on the user record.
// console.log(userRecord?.customClaims);
// });
// console.log('πŸš€ file: crud-user.ts:85 userNew:', userNew);

return { message: `Custom claims set on uid: ${data.uid}` };
} catch (error) {
throw error;
return { message: `Custom claims set on uid: ${data.uid}` };
} catch (error) {
throw error;
}
}
});
);
Loading

0 comments on commit 97892d9

Please sign in to comment.