race condition with search and firebase initializing
This commit is contained in:
@@ -9,7 +9,6 @@ import { NirvanaTheme } from './mui/NirvanaTheme';
|
|||||||
import { ElectronProvider } from './providers/ElectronProvider';
|
import { ElectronProvider } from './providers/ElectronProvider';
|
||||||
import { AuthProvider } from './providers/AuthProvider';
|
import { AuthProvider } from './providers/AuthProvider';
|
||||||
|
|
||||||
import './firebase/connect';
|
|
||||||
import ErrorParent from './providers/ErrorBoundary';
|
import ErrorParent from './providers/ErrorBoundary';
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
|
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useRef } from 'react';
|
import React, { useCallback, useRef, useState } from 'react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
@@ -17,21 +17,37 @@ import {
|
|||||||
import { blueGrey } from '@mui/material/colors';
|
import { blueGrey } from '@mui/material/colors';
|
||||||
import { FiActivity, FiInbox, FiSearch } from 'react-icons/fi';
|
import { FiActivity, FiInbox, FiSearch } from 'react-icons/fi';
|
||||||
import NirvanaAvatar from './NirvanaAvatar';
|
import NirvanaAvatar from './NirvanaAvatar';
|
||||||
import { useKey } from 'react-use';
|
import { useDebounce, useKey } from 'react-use';
|
||||||
import { useSnackbar } from 'notistack';
|
import { useSnackbar } from 'notistack';
|
||||||
import KeyboardShortcutLabel from './KeyboardShortcutLabel';
|
import KeyboardShortcutLabel from './KeyboardShortcutLabel';
|
||||||
|
import { searchUsers, User } from '../firebase/firestore';
|
||||||
|
|
||||||
const Conversations = () => {
|
const Conversations = () => {
|
||||||
const { enqueueSnackbar } = useSnackbar();
|
const { enqueueSnackbar } = useSnackbar();
|
||||||
|
|
||||||
const searchRef = useRef<HTMLInputElement>(null);
|
const searchRef = useRef<HTMLInputElement>(null);
|
||||||
|
const [searchVal, setSearchVal] = useState<string>('');
|
||||||
|
|
||||||
const onSearch = useCallback(() => {
|
const onSearchFocus = useCallback(() => {
|
||||||
enqueueSnackbar('search focused');
|
enqueueSnackbar('search focused');
|
||||||
if (searchRef?.current) searchRef.current.focus();
|
if (searchRef?.current) searchRef.current.focus();
|
||||||
}, []);
|
}, [enqueueSnackbar, searchRef]);
|
||||||
|
|
||||||
useKey('Shift', onSearch);
|
const [searchUsersResults, setSearchUsersResults] = useState<User[]>([]);
|
||||||
|
|
||||||
|
useKey('Shift', onSearchFocus);
|
||||||
|
|
||||||
|
const [, cancel] = useDebounce(
|
||||||
|
async () => {
|
||||||
|
if (searchVal) {
|
||||||
|
enqueueSnackbar('searching...', { variant: 'info' });
|
||||||
|
|
||||||
|
setSearchUsersResults(await searchUsers(searchVal));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
500,
|
||||||
|
[searchVal, enqueueSnackbar, setSearchUsersResults],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -51,11 +67,18 @@ const Conversations = () => {
|
|||||||
>
|
>
|
||||||
<FiSearch style={{ color: blueGrey[500] }} />
|
<FiSearch style={{ color: blueGrey[500] }} />
|
||||||
|
|
||||||
<Input placeholder={'Find or start a conversation'} inputRef={searchRef} />
|
<Input
|
||||||
|
onChange={(e) => setSearchVal(e.target.value)}
|
||||||
|
value={searchVal}
|
||||||
|
placeholder={'Find or start a conversation'}
|
||||||
|
inputRef={searchRef}
|
||||||
|
/>
|
||||||
|
|
||||||
<KeyboardShortcutLabel label="Shift" />
|
<KeyboardShortcutLabel label="Shift" />
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
|
{searchVal && <ListPeople people={searchUsersResults} />}
|
||||||
|
|
||||||
<List
|
<List
|
||||||
sx={{
|
sx={{
|
||||||
pt: 2,
|
pt: 2,
|
||||||
@@ -149,4 +172,39 @@ const Conversations = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function ListPeople({ people }: { people: User[] }) {
|
||||||
|
return (
|
||||||
|
<List
|
||||||
|
sx={{
|
||||||
|
pt: 2,
|
||||||
|
}}
|
||||||
|
subheader={
|
||||||
|
<ListSubheader>
|
||||||
|
<FiActivity />
|
||||||
|
<Typography variant="subtitle2"> Priority</Typography>
|
||||||
|
</ListSubheader>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{people.length === 0 && (
|
||||||
|
<Typography variant="caption">
|
||||||
|
Sorry please try someone else or invite them to nirvana.
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{people.map((person) => (
|
||||||
|
<ListItem key={`${person.uid}-searchUsers`}>
|
||||||
|
<ListItemButton selected={true}>
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar alt={person.displayName} src={person.photoUrl} />
|
||||||
|
</ListItemAvatar>
|
||||||
|
|
||||||
|
<ListItemText primary={person.displayName} />
|
||||||
|
|
||||||
|
<Typography variant={'caption'}>20 sec</Typography>
|
||||||
|
</ListItemButton>
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
);
|
||||||
|
}
|
||||||
export default Conversations;
|
export default Conversations;
|
||||||
|
|||||||
@@ -12,4 +12,4 @@ export const firebaseApp = initializeApp(devConfig);
|
|||||||
export const firebaseAuth = getAuth(firebaseApp);
|
export const firebaseAuth = getAuth(firebaseApp);
|
||||||
|
|
||||||
// Initialize Cloud Firestore and get a reference to the service
|
// Initialize Cloud Firestore and get a reference to the service
|
||||||
export const firestore = getFirestore(firebaseApp);
|
export const firestoreDb = getFirestore(firebaseApp);
|
||||||
|
|||||||
@@ -8,9 +8,14 @@ import {
|
|||||||
QueryDocumentSnapshot,
|
QueryDocumentSnapshot,
|
||||||
Timestamp,
|
Timestamp,
|
||||||
FieldValue,
|
FieldValue,
|
||||||
|
getDoc,
|
||||||
|
query,
|
||||||
|
where,
|
||||||
|
getDocs,
|
||||||
} from 'firebase/firestore';
|
} from 'firebase/firestore';
|
||||||
|
|
||||||
import { User as FirebaseUser } from 'firebase/auth';
|
import { User as FirebaseUser } from 'firebase/auth';
|
||||||
|
import { firestoreDb } from './connect';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UTILS
|
* UTILS
|
||||||
@@ -20,11 +25,15 @@ const converter = <T>() => ({
|
|||||||
fromFirestore: (snap: QueryDocumentSnapshot) => snap.data() as T,
|
fromFirestore: (snap: QueryDocumentSnapshot) => snap.data() as T,
|
||||||
});
|
});
|
||||||
|
|
||||||
const dataPoint = <T>(collectionPath: string) =>
|
const docPoint = <T>(collectionPath: string) =>
|
||||||
doc(getFirestore(), collectionPath).withConverter(converter<T>());
|
firestoreDb && doc(getFirestore(), collectionPath).withConverter(converter<T>());
|
||||||
|
|
||||||
|
const collectionPoint = <T>(collectionPath: string) =>
|
||||||
|
firestoreDb && collection(getFirestore(), collectionPath).withConverter(converter<T>());
|
||||||
|
|
||||||
const db = {
|
const db = {
|
||||||
user: (userId: string) => dataPoint<User>(`users/${userId}`),
|
users: collectionPoint<User>(`users`),
|
||||||
|
user: (userId: string) => docPoint<User>(`users/${userId}`),
|
||||||
};
|
};
|
||||||
|
|
||||||
export class User {
|
export class User {
|
||||||
@@ -65,3 +74,31 @@ export const createUser = async (user: FirebaseUser) => {
|
|||||||
throw new Error('Error creating user');
|
throw new Error('Error creating user');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const searchUsers = async (searchQuery: string): Promise<User[] | undefined> => {
|
||||||
|
try {
|
||||||
|
const emaildocSearchQuery = query(
|
||||||
|
db.users,
|
||||||
|
where('email', '>=', searchQuery.toUpperCase()),
|
||||||
|
where('email', '<=', searchQuery.toUpperCase() + '\uf8ff'),
|
||||||
|
);
|
||||||
|
|
||||||
|
const nameSearchQuery = query(
|
||||||
|
db.users,
|
||||||
|
where('displayName', '>=', searchQuery.toUpperCase()),
|
||||||
|
where('displayName', '<=', searchQuery.toUpperCase() + '\uf8ff'),
|
||||||
|
);
|
||||||
|
|
||||||
|
const emailquerySnap = await getDocs(emaildocSearchQuery);
|
||||||
|
const namequerySnap = await getDocs(nameSearchQuery);
|
||||||
|
|
||||||
|
return [
|
||||||
|
...emailquerySnap.docs.map((doc) => doc.data()),
|
||||||
|
...namequerySnap.docs.map((doc) => doc.data()),
|
||||||
|
];
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error: ', e);
|
||||||
|
|
||||||
|
throw new Error('Error');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user