-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Edit protest flow v3 #142
Closed
Closed
Edit protest flow v3 #142
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
1a46c92
edit button redirect url should be to edit instead of leader request
uriklar e651d42
Merge branch 'master' of https://github.com/guytepper/1km.co.il into …
uriklar 9142f0a
Fix redirect after protest update
uriklar b507edb
WIP
uriklar 75ac99a
Create leader request + assign leader when editing
uriklar a4b457a
Create edit
uriklar f36fe56
unique edited protest ids on user
uriklar f0a4861
Change edits implementation
uriklar da555b5
don't allow editing with more than 4 edits
uriklar 700fc72
change userRef and protestRef to user and protest
uriklar 98d4446
added some utility functions that might now get used...
uriklar 2f42381
Add diff to edit document
uriklar 7a175e3
added setEditAsViewed method
uriklar 8e234e1
edits admin wip
uriklar a27b708
Admin functionality
uriklar 5cf936c
admin css
uriklar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
@@ -1,5 +1,6 @@ | ||||
import firebase, { firestore } from '../firebase'; | ||||
import * as geofirestore from 'geofirestore'; | ||||
import { arrayToHashMap } from '../utils'; | ||||
const GeoFirestore = geofirestore.initializeApp(firestore); | ||||
|
||||
// async function verifyRecaptcha(token) { | ||||
|
@@ -120,6 +121,16 @@ export async function fetchProtest(protestId) { | |||
} | ||||
} | ||||
|
||||
export async function fetchUser(userId) { | ||||
const user = await firestore.collection('users').doc(userId).get(); | ||||
|
||||
if (user.exists) { | ||||
return user.data(); | ||||
} else { | ||||
return false; | ||||
} | ||||
} | ||||
|
||||
export async function uploadFile(params) { | ||||
const request = await fetch('http://localhost:5001/onekm-50c7f/us-central1/uploadImage', { | ||||
method: 'post', | ||||
|
@@ -180,6 +191,16 @@ export async function getProtestsForLeader(uid) { | |||
return protests; | ||||
} | ||||
|
||||
export async function fetchProtestsById(ids) { | ||||
const protests = await firestore.collection('protests').where(firestore.FieldPath.documentId(), 'in', ids).get(); | ||||
return protests.map((doc) => doc.data()); | ||||
} | ||||
|
||||
export async function fetchUsersById(ids) { | ||||
const users = await firestore.collection('users').where(firestore.FieldPath.documentId(), 'in', ids).get(); | ||||
return users.map((doc) => doc.data()); | ||||
} | ||||
|
||||
export function createLeaderRequestId(userId, protestId) { | ||||
return `${userId}${protestId}`; | ||||
} | ||||
|
@@ -198,6 +219,19 @@ export async function setPhoneNumberForUser(uid, phoneNumber) { | |||
await firestore.collection('users').doc(uid).update({ phoneNumber }); | ||||
} | ||||
|
||||
export async function setProtestEditsForUser(user, protestId) { | ||||
await firestore | ||||
.collection('users') | ||||
.doc(user.uid) | ||||
.update({ | ||||
edits: [...new Set([...(user.edits || []), protestId])], | ||||
}); | ||||
} | ||||
|
||||
export async function setEditAsViewed(id) { | ||||
firestore.collection('protest_edits').doc(id).update({ status: 'viewed' }); | ||||
} | ||||
|
||||
// return true is the protest exist in the database | ||||
export async function isProtestValid(protestId) { | ||||
try { | ||||
|
@@ -264,6 +298,32 @@ export function handleSignIn() { | |||
firebase.auth().signInWithRedirect(provider); | ||||
} | ||||
|
||||
export async function createProtestEdit(userId, protestId, diff) { | ||||
await firestore.collection('protest_edits').add({ | ||||
userId, | ||||
protestId, | ||||
diff, | ||||
created_at: firebase.firestore.FieldValue.serverTimestamp(), | ||||
status: 'pending', | ||||
}); | ||||
} | ||||
|
||||
export async function fetchPendingEdits() { | ||||
const editsRef = firestore.collection('protest_edits'); | ||||
const query = editsRef.where('status', '==', 'pending'); | ||||
|
||||
const querySnapshot = await query.get(); | ||||
const edits = []; | ||||
|
||||
querySnapshot.forEach(function (doc) { | ||||
edits.push({ id: doc.id, ...doc.data() }); | ||||
}); | ||||
|
||||
console.log('edits in function', edits); | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
|
||||
return edits; | ||||
} | ||||
|
||||
/////////////////////////////////////////////////////// | ||||
// functions to be used by the admin page | ||||
// in order to show data and complete the process of | ||||
|
@@ -282,15 +342,19 @@ export async function listLeaderRequests() { | |||
return leaderRequests; | ||||
} | ||||
|
||||
export async function makeUserProtestLeader(protestId, userId) { | ||||
return firestore | ||||
.collection('protests') | ||||
.doc(protestId) | ||||
.update({ | ||||
'roles.leader': firebase.firestore.FieldValue.arrayUnion(userId), | ||||
}); | ||||
} | ||||
|
||||
// When super-admin approves a protest-user request | ||||
export async function assignRoleOnProtest({ userId, protestId, requestId, status, adminId }) { | ||||
if (status === 'approved') { | ||||
await firestore | ||||
.collection('protests') | ||||
.doc(protestId) | ||||
.update({ | ||||
'roles.leader': firebase.firestore.FieldValue.arrayUnion(userId), | ||||
}); | ||||
await makeUserProtestLeader(protestId, userId); | ||||
} | ||||
|
||||
// Update request | ||||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import { useEffect } from 'react'; | ||
import { fetchPendingEdits, fetchProtest, fetchUser, setEditAsViewed } from '../../api'; | ||
import React, { useState } from 'react'; | ||
import { formatDate } from '../../utils'; | ||
|
||
function getFieldName(fieldKey) { | ||
switch (fieldKey) { | ||
case 'displayName': | ||
return 'שם המקום'; | ||
case 'streetAddress': | ||
return 'כתובת'; | ||
case 'coords': | ||
return 'קואורדינטות'; | ||
case 'whatsAppLink': | ||
return 'לינק לוואצאפ'; | ||
case 'telegramLink': | ||
return 'לינק לטלגרם'; | ||
case 'notes': | ||
return 'הערות'; | ||
case 'dateTimeList': | ||
return 'תאריך ושעה'; | ||
default: | ||
return ''; | ||
} | ||
} | ||
|
||
function EditField({ diff, keyName, type }) { | ||
const value = (diff[keyName] || {})[type]; | ||
|
||
switch (keyName) { | ||
case 'dateTimeList': | ||
return value.map((dt) => ( | ||
<div key={`${dt.date}-${dt.time}`}> | ||
{formatDate(dt.date)} - {dt.time} | ||
</div> | ||
)); | ||
default: | ||
return <div>{value}</div>; | ||
} | ||
} | ||
|
||
function EditRow({ created_at, diff = {}, userId, protestId, id }) { | ||
const [expanded, setExpanded] = useState(false); | ||
const [protest, setProtest] = useState(null); | ||
const [user, setUser] = useState(null); | ||
const [viewed, setViewed] = useState(false); | ||
|
||
useEffect(() => { | ||
if (expanded) { | ||
fetchProtest(protestId).then((p) => { | ||
if (p) { | ||
setProtest(p); | ||
} | ||
}); | ||
|
||
fetchUser(userId).then((u) => { | ||
if (u) { | ||
setUser(u); | ||
} | ||
}); | ||
} | ||
}, [expanded, protestId, userId]); | ||
|
||
if (viewed) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<> | ||
<div style={{ display: 'flex', alignItems: 'center' }}> | ||
<div>{formatDate(created_at.toDate())}</div> | ||
<div> | ||
{Object.keys(diff).map((key) => ( | ||
<div style={{ padding: '16px', display: 'flex' }} key={key}> | ||
<div style={{ marginBottom: '8px' }}> | ||
<b>{getFieldName(key)}</b> | ||
</div> | ||
<div style={{ paddingRight: '10px' }}> | ||
<span style={{ textDecoration: 'line-through' }}> | ||
<EditField keyName={key} diff={diff} type="oldValue" /> | ||
</span> | ||
<span> | ||
<EditField keyName={key} diff={diff} type="newValue" /> | ||
</span> | ||
</div> | ||
</div> | ||
))} | ||
</div> | ||
<div onClick={() => setExpanded(true)}>פרטים נוספים</div> | ||
<button | ||
onClick={() => { | ||
setEditAsViewed(id); | ||
setViewed(true); | ||
}} | ||
> | ||
ראיתי | ||
</button> | ||
</div> | ||
|
||
{expanded && protest && user && ( | ||
<div> | ||
{JSON.stringify(protest)} + {JSON.stringify(user)} | ||
</div> | ||
)} | ||
</> | ||
); | ||
} | ||
|
||
async function _fetchPendingEdits(setEdits) { | ||
const result = await fetchPendingEdits(); | ||
setEdits(result); | ||
} | ||
|
||
function useFetchEdits() { | ||
const [edits, setEdits] = useState(null); | ||
|
||
useEffect(() => { | ||
_fetchPendingEdits(setEdits); | ||
}, []); | ||
|
||
return { | ||
edits, | ||
}; | ||
} | ||
export default function EditsAdmin() { | ||
const { edits } = useFetchEdits(); | ||
if (!edits) { | ||
return <div>Loading...</div>; | ||
} | ||
|
||
return ( | ||
<div> | ||
{edits.map((edit) => ( | ||
<EditRow {...edit} key={edit.uid} /> | ||
))} | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you want to push the new protestsId into the edits list, I would use the following - https://firebase.google.com/docs/reference/js/firebase.firestore.FieldValue#arrayunion
It has been done similarly here -
1km.co.il/src/api/index.js
Line 350 in 5cf936c
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the docs we don't need to use a
Set
to keep the array unique in firestore.