Skip to content

Commit

Permalink
Update getMembers.ts
Browse files Browse the repository at this point in the history
  • Loading branch information
OronNadiv committed Aug 24, 2024
1 parent 7ef8c2e commit aeab0d4
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 84 deletions.
26 changes: 26 additions & 0 deletions functions/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions functions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@
"underscore": "^1.13.2"
},
"devDependencies": {
"@types/bluebird": "^3.5.42",
"@types/luxon": "^2.3.1",
"@types/node": "^14.18.12",
"@types/underscore": "^1.11.15",
"dayjs": "^1.11.0",
"firebase-functions-test": "^0.3.3",
"json-to-ts": "^1.7.0",
Expand Down
64 changes: 36 additions & 28 deletions functions/src/getMembers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@ import {
ZIP
} from './fields'
import * as _ from 'underscore'

const {
warn
} = require("firebase-functions/logger")
import { warn } from "firebase-functions/logger"

const defaultVisibility: Visibility = {
[UID]: VisibilityEnum.MEMBERS,
Expand All @@ -40,25 +37,27 @@ const defaultVisibility: Visibility = {
}

const GetMembers = (admin: Admin.app.App) => {
let foundCurrentUser = false

const firestore = admin.firestore()

return async (data: any, context?: https.CallableContext) => {
const hasContext = !!context
const hasAuth = hasContext && !!context.auth
const hasUid = hasAuth && !!context.auth.uid
if (!hasContext || !hasAuth || !hasUid) {
warn("unauthenticated.", {hasContext, hasAuth, hasUid})

let foundCurrentUser = false

if (!context || !context.auth || !context.auth.uid) {
warn("unauthenticated.", {
hasContext: !!context,
hasAuth: context && !!context.auth,
hasUid: context && context.auth && !!context.auth.uid
})

throw new https.HttpsError(
'unauthenticated',
'unauthenticated.'
)
}

const applyFilters = (user: User) => {
if (!hasAuth) {
if (!context || !context.auth) {
throw new https.HttpsError(
'permission-denied',
JSON.stringify({
Expand All @@ -67,12 +66,16 @@ const GetMembers = (admin: Admin.app.App) => {
})
)
}

if (context.auth.uid === user.uid) {
foundCurrentUser = true
if (!calc(user).isAMember) {
warn("permission-denied. Current user is not a memeber.", {hasContext, hasAuth, hasUid})

warn("permission-denied. Current user is not a memeber.", {
hasContext: context,
hasAuth: context && !!context.auth,
hasUid: context && context.auth && !!context.auth.uid
})

throw new https.HttpsError(
'permission-denied',
JSON.stringify({
Expand Down Expand Up @@ -111,24 +114,29 @@ const GetMembers = (admin: Admin.app.App) => {
users.push(user)
})

if(!foundCurrentUser){
warn("permission-denied. Could not find current user.", {hasContext, hasAuth, hasUid})

throw new https.HttpsError(
'permission-denied',
JSON.stringify({
status: 403,
message: 'user is not a member.'
})
)
}

users = _.chain(users)
.filter((user: User) => {
return calc(user).isAMember
})
.map(applyFilters)
.value()

if (!foundCurrentUser) {
warn("permission-denied. Could not find current user.", {
hasContext: !!context,
hasAuth: context && !!context.auth,
hasUid: context && context.auth && !!context.auth.uid
})

throw new https.HttpsError(
'permission-denied',
JSON.stringify({
status: 403,
message: 'user is not a member.'
})
)
}

return users
}
}
Expand Down
128 changes: 72 additions & 56 deletions src/pages/members-page/MembersPage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { functions } from '../../firebase'
import React, { useEffect, useState } from 'react'
import React, { useCallback, useEffect, useState } from 'react'
import { DISPLAY_NAME, UID } from '../../fields'
import * as PropTypes from 'prop-types'
import * as Sentry from '@sentry/browser'
Expand All @@ -20,7 +20,7 @@ import { withRouter, RouteComponentProps } from 'react-router-dom'
import { compose, findWhere, isString, sortBy } from 'underscore'
import { MEMBERS, ROOT } from '../../urls'
import SearchBox from '../../components/SearchBox'
import { Map as IMap } from 'immutable'
import { fromJS, List as IList, Map as IMap } from 'immutable'
import { getAvatar, IRedisState, IUser } from '../../entities/User'
import { User } from 'firebase/auth'
import { FunctionsError, httpsCallable } from 'firebase/functions'
Expand All @@ -31,11 +31,11 @@ interface Props extends RouteComponentProps {
}

function MembersPage({
firebaseUser,
location: { pathname },
history,
userData
}: Props) {
firebaseUser,
location: { pathname },
history,
userData
}: Props) {
const userDataJS: IUser = userData.toJS()
const useStyles = makeStyles(() => ({
chipAvatar: {
Expand All @@ -48,23 +48,25 @@ function MembersPage({
const [isLoading, setIsLoading] = useState(true)
const [showError, setShowError] = useState(false)
const [users, setUsers] = useState<IUser[]>([])
// @ts-ignore
const [filteredUsers, setFilteredUsers] = useState(new IList())

useEffect(() => {
if (!firebaseUser) {
return
}
;(async function() {
; (async function () {
try {
// return setUsers(require('./members.json'))
const getMembers = httpsCallable(functions, 'getMembers')
const resp : {data: IUser[]} = await getMembers() as {data: IUser[]}
const resp: { data: IUser[] } = await getMembers() as { data: IUser[] }
const data: IUser[] = sortBy(resp.data, (user: IUser) => {
if (!user.displayName) {
return
}
return user.uid === firebaseUser.uid
? '_'
: user.displayName.toLowerCase()
? '_'
: user.displayName.toLowerCase()
})
setUsers(data)
} catch (err) {
Expand Down Expand Up @@ -117,16 +119,29 @@ function MembersPage({
history.push(MEMBERS)
}

const getChips = () => {
let filteredUsers = users || []
if (search) {
const applyFilter = useCallback(() => {
let tmpUsers = users || []

console.log("search:", search, !!search)
console.log("users size:", users.length)

if (!!search) {
const searcher = new FuzzySearch(users, [DISPLAY_NAME], {
caseSensitive: false
})
filteredUsers = searcher.search(search)
tmpUsers = searcher.search(search)
}
console.log("tmpUsers size:", tmpUsers.length)
setFilteredUsers(fromJS(tmpUsers))
}, [users, search])

return filteredUsers.map((user) => {
useEffect(() => {
applyFilter()
}, [applyFilter])

const getChips = () => {
return filteredUsers.map((item: any) => {
const user: IUser = item.toJS()
const label = user.displayName

function getColor() {
Expand All @@ -141,19 +156,20 @@ function MembersPage({
}

const avatarUrl = getAvatar(user)
console.log("user.uid:", user.uid)
return (
<Chip
className="my-1 mx-1"
avatar={
<Avatar className={classes.chipAvatar} src={avatarUrl}>
{!avatarUrl && <DirectionsRun />}
</Avatar>
}
onClick={() => handleChipSelected(user)}
key={user.uid}
label={label}
color={getColor()}
/>
<Chip
className="my-1 mx-1"
avatar={
<Avatar className={classes.chipAvatar} src={avatarUrl}>
{!avatarUrl && <DirectionsRun />}
</Avatar>
}
onClick={() => handleChipSelected(user)}
key={user.uid}
label={label}
color={getColor()}
/>
)
})
}
Expand All @@ -163,29 +179,29 @@ function MembersPage({
return <></>
}
return (
<>
{showError && (
<Snackbar
open
autoHideDuration={6000}
message={'Oops! Something went wrong.'}
/>
)}
{!!selected && (
<UserProfile
// @ts-ignore
user={selected}
style={{ width: 250 }}
onClose={handleDrawerClosed}
/>
)}
<SearchBox onChange={setSearch} />
<Paper className="px-2 py-3">
<div className="d-flex justify-content-between flex-wrap">
{isLoading ? <CircularProgress className="mx-auto" /> : getChips()}
</div>
</Paper>
</>
<>
{showError && (
<Snackbar
open
autoHideDuration={6000}
message={'Oops! Something went wrong.'}
/>
)}
{!!selected && (
<UserProfile
// @ts-ignore
user={selected}
style={{ width: 250 }}
onClose={handleDrawerClosed}
/>
)}
<SearchBox onChange={setSearch} />
<Paper className="px-2 py-3">
<div className="d-flex justify-content-between flex-wrap">
{isLoading ? <CircularProgress className="mx-auto" /> : getChips()}
</div>
</Paper>
</>
)
}

Expand All @@ -200,13 +216,13 @@ const mapStateToProps = ({ currentUser: { firebaseUser, userData } }: IRedisStat
return {
firebaseUser,
userData: userData ||
// @ts-ignore
new IMap()
// @ts-ignore
new IMap()
}
}

export default compose(
withRouter,
LoggedInState(),
connect(mapStateToProps)
withRouter,
LoggedInState(),
connect(mapStateToProps)
)(MembersPage)

0 comments on commit aeab0d4

Please sign in to comment.