Skip to content

Commit

Permalink
Merge 3a85e05 into 8163169
Browse files Browse the repository at this point in the history
  • Loading branch information
alromh87 authored Sep 10, 2020
2 parents 8163169 + 3a85e05 commit 5d43a9f
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 44 deletions.
81 changes: 81 additions & 0 deletions functions/src/Integrations/user-stats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import * as functions from 'firebase-functions'
import { db } from '../Firebase/firestoreDB'


export const countHowTos = functions.firestore
.document('v3_howtos/{id}')
.onWrite(async (change, context) => {

updateStats(change, 'v3_howtos', 'howToCount')

})

export const countEvents = functions.firestore
.document('v3_events/{id}')
.onWrite(async (change, context) => {

updateStats(change, 'v3_events', 'eventCount')

})

function updateStats(change, collection, target){

const info = change.after.exists ? change.after.data() : null
const prevInfo = change.before.exists ? change.before.data() : null
const userStatsRef = db.collection('v3_users/');

let delta = 0

if (info !== null && info.moderation === 'accepted' && prevInfo !== null && prevInfo.Moderation !== 'accepted') { // Increment if now accepted and previously different
delta = 1
} else if (prevInfo !== null && prevInfo.moderation === 'accepted' && (info === null || info.moderation !== 'accepted')) { // Decrement if previously accepted and now erased or moderation changed
delta = -1
} else {
return null
}

console.log('Update ', collection, ' delta: ', delta )

return userStatsRef.doc(info._createdBy).update({'stats':{
[target]: admin.firestore.FieldValue.increment(delta)
}}).catch(e => {
console.log(e);
// In case stats for user are inexistent we compute from all his records, Only triggers if no user exist (new Collection)
// computeUserStats(info._createdBy)
})
}

// Compute one user stats
function computeUserStats(owner){

const userStatsRef = db.collection('v3_users/')

db.collection('v3_howtos').where("_createdBy", "==", owner).where("moderation", "==", "accepted")
.get()
.then(querySnapshot => {
let count = 0;
querySnapshot.forEach(doc => {
count++;
});
console.log('Accepted howtos for', owner ,',count: ', count);
userStatsRef.doc(owner).set({'stats':{
howToCount: count
}}, {merge: true});
return null
}).catch(() => null);

db.collection('v3_events').where("_createdBy", "==", owner).where("moderation", "==", "accepted")
.get()
.then(querySnapshot => {
let count = 0;
querySnapshot.forEach(doc => {
count++;
});
console.log('Accepted events for', owner ,',count: ', count);
userStatsRef.doc(owner).set({'stats':{
eventCount: count
}}, {merge: true});
return null
}).catch(() => null);
}

3 changes: 3 additions & 0 deletions functions/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as IntegrationsSlack from './Integrations/firebase-slack'
import * as IntegrationsDiscord from './Integrations/firebase-discord'
import { FirebaseUserBackup } from './Integrations/firebase-userBackup'
import * as IntegrationsEmail from './Integrations/firebase-email'
import * as UserStats from './Integrations/user-stats'
import * as Admin from './admin'

// the following endpoints are exposed for use by various triggers
Expand All @@ -23,6 +24,8 @@ exports.notifyHowToAccepted = IntegrationsDiscord.notifyHowToAccepted
exports.notifyEventAccepted = IntegrationsDiscord.notifyEventAccepted
exports.firebaseUserBackup = FirebaseUserBackup
exports.emailNotificationDemo = IntegrationsEmail.notifyEmailDemo
exports.countEvents = UserStats.countEvents
exports.countHowTos = UserStats.countHowTos
// CC Note, 2020-04-40
// folder-based naming conventions should be encourage from now on
exports.adminGetUserEmail = Admin.getUserEmail
2 changes: 1 addition & 1 deletion scripts/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ checkBrowsers(paths.appPath, isInteractive)
function build(previousFileSizes) {
console.log('Creating an optimized production build...')

let compiler = webpack(config)
const compiler = webpack(config)
return new Promise((resolve, reject) => {
compiler.run((err, stats) => {
let messages
Expand Down
4 changes: 3 additions & 1 deletion src/components/ElWithBeforeIcon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ interface IProps {
width?: string
ticked?: boolean
contain?: boolean
mr?: number
}

export const ElWithBeforeIcon: FunctionComponent<IProps> = ({
Expand All @@ -17,6 +18,7 @@ export const ElWithBeforeIcon: FunctionComponent<IProps> = ({
children,
ticked,
contain,
mr,
}) => {
let after: any
if (ticked) {
Expand All @@ -35,7 +37,7 @@ export const ElWithBeforeIcon: FunctionComponent<IProps> = ({

return (
<Box
mr={4}
mr={mr || 4}
pl="30px"
sx={{
position: 'relative',
Expand Down
6 changes: 6 additions & 0 deletions src/models/user.models.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export interface IUser {
country?: string | null
location?: ILocation | null
year?: ISODateString
stats?: IUserStats
}

interface IExternalLink {
Expand All @@ -51,6 +52,11 @@ interface IExternalLink {
| 'instagram'
}

interface IUserStats {
howToCount: number
eventCount: number
}

export type IUserDB = IUser & DBDoc

export type UserRole = 'super-admin' | 'subscriber' | 'admin'
115 changes: 73 additions & 42 deletions src/pages/User/content/UserPage/UserPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ import Slider from 'react-slick'
import styled from 'styled-components'
import Icon from 'src/components/Icons'
import Flex from 'src/components/Flex'
// import ElWithBeforeIcon from 'src/components/ElWithBeforeIcon'
import ElWithBeforeIcon from 'src/components/ElWithBeforeIcon'
import { zIndex } from 'src/themes/styled.theme'
import Workspace from 'src/pages/User/workspace/Workspace'
import { Text } from 'src/components/Text'
import { Link } from 'src/components/Links'

import theme from 'src/themes/styled.theme'
import { replaceDashesWithSpaces } from 'src/utils/helpers'
Expand All @@ -33,9 +34,9 @@ import PPIcon from 'src/assets/images/plastic-types/pp.svg'
import PSIcon from 'src/assets/images/plastic-types/ps.svg'
import PVCIcon from 'src/assets/images/plastic-types/pvc.svg'

// import EventsIcon from 'src/assets/icons/icon-events.svg'
import EventsIcon from 'src/assets/icons/icon-events.svg'
// import ExpertIcon from 'src/assets/icons/icon-expert.svg'
// import HowToCountIcon from 'src/assets/icons/icon-how-to.svg'
import HowToCountIcon from 'src/assets/icons/icon-how-to.svg'
// import V4MemberIcon from 'src/assets/icons/icon-v4-member.svg'

import { IUploadedFileMeta } from 'src/stores/storage'
Expand Down Expand Up @@ -114,21 +115,22 @@ const MobileBadge = styled.div`
}
`

// const CommitmentBox = styled.div`
// border: 2px solid black;
// border-radius: 10px;
// padding: 20px;
// background-color: ${theme.colors.background};
// margin-bottom: 20px;
// `
const UserStatsBox = styled.div`
margin-top: 15px;
border: 2px solid black;
border-radius: 10px;
padding: 10px;
background-color: ${theme.colors.background};
margin-bottom: 20px;
`

// const CommitmentBoxItem = styled.div`
// margin-top: 15px;
const UserStatsBoxItem = styled.div`
margin-top: 15px;
// &:first-child {
// margin-top: 0;
// }
// `
&:first-child {
margin-top: 0;
}
`

const ProfileWrapper = styled(Box)`
/* margin-top: 40px;
Expand Down Expand Up @@ -225,32 +227,52 @@ export class UserPage extends React.Component<
})
}
// Comment on 6.05.20 by BG : renderCommitmentBox commented for now, will be reused with #974
// public renderCommitmentBox(isExpert?: boolean, isV4Member?: boolean) {
// return (
// <CommitmentBox>
// {isExpert && (
// <CommitmentBoxItem>
// <ElWithBeforeIcon IconUrl={ExpertIcon} height="25px">
// Expert
// </ElWithBeforeIcon>
// </CommitmentBoxItem>
// )}
// {isV4Member && (
// <CommitmentBoxItem>
// <ElWithBeforeIcon IconUrl={V4MemberIcon}>
// V4 Member
// </ElWithBeforeIcon>
// </CommitmentBoxItem>
// )}
// <CommitmentBoxItem>
// <ElWithBeforeIcon IconUrl={EventsIcon}>0</ElWithBeforeIcon>
// </CommitmentBoxItem>
// <CommitmentBoxItem>
// <ElWithBeforeIcon IconUrl={HowToCountIcon}>0</ElWithBeforeIcon>
// </CommitmentBoxItem>
// </CommitmentBox>
// )
// }
public renderUserStatsBox(user: IUserPP) {
if (!user.stats) {
user.stats = { howToCount: 0, eventCount: 0 }
}

return (
<UserStatsBox>
{/* {isExpert && (
<UserStatsBoxItem>
<ElWithBeforeIcon IconUrl={ExpertIcon} height="25px">
Expert
</ElWithBeforeIcon>
</UserStatsBoxItem>
)} */}
{user.location && (
<Link color={'black'} to={'/map/#' + user.userName}>
<UserStatsBoxItem>
<Icon glyph="location-on"></Icon>
<span> {user.location?.country}</span>
</UserStatsBoxItem>
</Link>
)}
{/* {isV4Member && (
<UserStatsBoxItem>
<ElWithBeforeIcon IconUrl={V4MemberIcon}>
V4 Member
</ElWithBeforeIcon>
</UserStatsBoxItem>
)} */}
{user.stats.howToCount > 0 && (
<UserStatsBoxItem>
<ElWithBeforeIcon IconUrl={HowToCountIcon} mr={2}>
How-to: {user.stats.howToCount}
</ElWithBeforeIcon>
</UserStatsBoxItem>
)}
{user.stats.eventCount > 0 && (
<UserStatsBoxItem>
<ElWithBeforeIcon IconUrl={EventsIcon} mr={2}>
Events: {user.stats.eventCount}
</ElWithBeforeIcon>
</UserStatsBoxItem>
)}
</UserStatsBox>
)
}

public renderPlasticTypes(plasticTypes: Array<PlasticTypeLabel>) {
function renderIcon(type: string) {
Expand Down Expand Up @@ -373,6 +395,13 @@ export class UserPage extends React.Component<
},
)
}
// TODO check if user exist and have created how-to or events
const shouldRenderUserStatsBox =
user &&
(user.location ||
(user.stats && (user.stats.howToCount || user.stats.eventCount)))
? true
: false

return (
<ProfileWrapper mt={4} mb={6}>
Expand Down Expand Up @@ -448,6 +477,8 @@ export class UserPage extends React.Component<
>
<MobileBadge>
<Image src={workspaceBadgeSrc} />

{shouldRenderUserStatsBox && this.renderUserStatsBox(user)}
</MobileBadge>
</Box>
</ProfileContentWrapper>
Expand Down

0 comments on commit 5d43a9f

Please sign in to comment.