[New Feature] Apply graph strategy
This commit is contained in:
@@ -1,9 +1,19 @@
|
||||
{
|
||||
"hosting": {
|
||||
"public": "public",
|
||||
"rewrites": [{
|
||||
"source": "**",
|
||||
"destination": "/index.html"
|
||||
}]
|
||||
"rewrites": [
|
||||
{
|
||||
"source": "/bundle-v0.4.js",
|
||||
"destination": "/bundle-v0.4.js"
|
||||
},
|
||||
{
|
||||
"source": "/favicon.ico",
|
||||
"destination": "/favicon.ico"
|
||||
},
|
||||
{
|
||||
"source": "**",
|
||||
"destination": "/index.html"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
"@types/react-infinite-scroller": "^1.0.4",
|
||||
"amazon-cognito-identity-js": "^1.21.0",
|
||||
"aws-sdk": "^2.132.0",
|
||||
"axios": "^0.16.1",
|
||||
"axios": "^0.16.2",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"classnames": "^2.2.5",
|
||||
"crypto-js": "^3.1.9-1",
|
||||
@@ -28,7 +28,8 @@
|
||||
"faker": "^4.1.0",
|
||||
"file-loader": "^0.11.1",
|
||||
"firebase": "^4.6.2",
|
||||
"inversify": "^4.3.0",
|
||||
"install": "^0.10.2",
|
||||
"inversify": "^4.6.0",
|
||||
"keycode": "^2.1.9",
|
||||
"lodash": "^4.17.4",
|
||||
"material-ui": "^0.19.4",
|
||||
@@ -36,6 +37,7 @@
|
||||
"morgan": "^1.8.1",
|
||||
"node-env-file": "^0.1.8",
|
||||
"node-sass": "^4.5.2",
|
||||
"npm": "^5.6.0",
|
||||
"prop-types": "^15.6.0",
|
||||
"react": "^16.0.0",
|
||||
"react-addons-test-utils": "^15.6.2",
|
||||
@@ -43,7 +45,7 @@
|
||||
"react-dom": "^16.0.0",
|
||||
"react-event-listener": "^0.5.1",
|
||||
"react-hot-loader": "^3.1.3",
|
||||
"react-infinite-scroller": "^1.1.1",
|
||||
"react-infinite-scroller": "^1.1.2",
|
||||
"react-linkify": "^0.2.1",
|
||||
"react-parallax": "^1.4.4",
|
||||
"react-redux": "^5.0.6",
|
||||
|
||||
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
@@ -122,7 +122,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/bundle-v0.3.js"></script>
|
||||
<script src="/bundle-v0.5.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -15,13 +15,16 @@ import { AuthorizeActionType } from 'constants/authorizeActionType'
|
||||
|
||||
// - Import services
|
||||
import { IAuthorizeService } from 'core/services/authorize'
|
||||
import { IServiceProvider, ServiceProvide } from 'core/factories'
|
||||
|
||||
// - Import actions
|
||||
import * as globalActions from 'actions/globalActions'
|
||||
import { provider } from '../socialEngine'
|
||||
import { SocialProviderTypes } from 'core/socialProviderTypes'
|
||||
|
||||
const serviceProvider: IServiceProvider = new ServiceProvide()
|
||||
const authorizeService: IAuthorizeService = serviceProvider.createAuthorizeService()
|
||||
/**
|
||||
* Get service providers
|
||||
*/
|
||||
const authorizeService: IAuthorizeService = provider.get<IAuthorizeService>(SocialProviderTypes.AuthorizeService)
|
||||
|
||||
/* _____________ CRUD DB _____________ */
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// - Import domain
|
||||
import { User } from 'core/domain/users'
|
||||
import { Circle, UserFollower } from 'core/domain/circles'
|
||||
import { User, Profile } from 'core/domain/users'
|
||||
import { Circle, UserTie } from 'core/domain/circles'
|
||||
import { SocialError } from 'core/domain/common'
|
||||
|
||||
// - Import utility components
|
||||
@@ -15,11 +15,17 @@ import * as postActions from 'actions/postActions'
|
||||
import * as userActions from 'actions/userActions'
|
||||
import * as notifyActions from 'actions/notifyActions'
|
||||
|
||||
import { IServiceProvider,ServiceProvide } from 'core/factories'
|
||||
import { IServiceProvider, ServiceProvide } from 'core/factories'
|
||||
import { ICircleService } from 'core/services/circles'
|
||||
import { SocialProviderTypes } from 'core/socialProviderTypes'
|
||||
import { provider } from '../socialEngine'
|
||||
import { IUserTieService } from 'core/services/circles'
|
||||
|
||||
const serviceProvider: IServiceProvider = new ServiceProvide()
|
||||
const circleService: ICircleService = serviceProvider.createCircleService()
|
||||
/**
|
||||
* Get service providers
|
||||
*/
|
||||
const circleService: ICircleService = provider.get<ICircleService>(SocialProviderTypes.CircleService)
|
||||
const userTieService: IUserTieService = provider.get<IUserTieService>(SocialProviderTypes.UserTieService)
|
||||
|
||||
/* _____________ CRUD DB _____________ */
|
||||
|
||||
@@ -33,10 +39,9 @@ export let dbAddCircle = (circleName: string) => {
|
||||
let uid: string = getState().authorize.uid
|
||||
let circle: Circle = {
|
||||
creationDate: moment().unix(),
|
||||
name: circleName,
|
||||
users: {}
|
||||
name: circleName
|
||||
}
|
||||
return circleService.addCircle(uid,circle).then((circleKey: string) => {
|
||||
return circleService.addCircle(uid, circle).then((circleKey: string) => {
|
||||
circle.id = circleKey
|
||||
circle.ownerId = uid
|
||||
dispatch(addCircle(circle))
|
||||
@@ -47,31 +52,29 @@ export let dbAddCircle = (circleName: string) => {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a user in a circle
|
||||
* @param {string} cid is circle identifier
|
||||
* @param {User} userFollowing is the user for following
|
||||
* Update user in circle/circles
|
||||
*/
|
||||
export let dbAddFollowingUser = (cid: string, userFollowing: UserFollower) => {
|
||||
export let dbUpdateUserInCircles = (circleIdList: string[], userFollowing: UserTie) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
const state = getState()
|
||||
let uid: string = state.authorize.uid
|
||||
let user: User = { ...state.user.info[uid], userId: uid }
|
||||
|
||||
let uid: string = getState().authorize.uid
|
||||
let user: User = getState().user.info[uid]
|
||||
|
||||
let userCircle: User = {
|
||||
creationDate: moment().unix(),
|
||||
fullName: userFollowing.fullName,
|
||||
avatar: userFollowing.avatar || ''
|
||||
}
|
||||
let userFollower: UserFollower = {
|
||||
creationDate: moment().unix(),
|
||||
fullName: user.fullName,
|
||||
avatar: user.avatar || '',
|
||||
approved: false
|
||||
}
|
||||
|
||||
return circleService.addFollowingUser(uid,cid,userCircle,userFollower,userFollowing.userId as string)
|
||||
return userTieService.tieUseres(
|
||||
{ userId: user.userId!, fullName: user.fullName, avatar: user.avatar, approved: false },
|
||||
{ userId: userFollowing.userId!, fullName: userFollowing.fullName, avatar: userFollowing.avatar, approved: false },
|
||||
circleIdList
|
||||
)
|
||||
.then(() => {
|
||||
dispatch(addFollowingUser(uid, cid, userFollowing.userId as string, { ...userCircle } as User))
|
||||
dispatch(addFollowingUser(
|
||||
new UserTie(
|
||||
userFollowing.userId!,
|
||||
moment().unix(),
|
||||
userFollowing.fullName,
|
||||
userFollowing.avatar,
|
||||
false,
|
||||
circleIdList
|
||||
)))
|
||||
|
||||
dispatch(notifyActions.dbAddNotification(
|
||||
{
|
||||
@@ -89,18 +92,16 @@ export let dbAddFollowingUser = (cid: string, userFollowing: UserFollower) => {
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a user from a circle
|
||||
* @param {string} cid is circle identifier
|
||||
* @param {string} userFollowingId following user identifier
|
||||
* Delete following user
|
||||
*/
|
||||
export let dbDeleteFollowingUser = (cid: string, userFollowingId: string) => {
|
||||
export let dbDeleteFollowingUser = (userFollowingId: string) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
|
||||
let uid: string = getState().authorize.uid
|
||||
|
||||
return circleService.deleteFollowingUser(uid,cid,userFollowingId)
|
||||
return userTieService.removeUsersTie(uid, userFollowingId)
|
||||
.then(() => {
|
||||
dispatch(deleteFollowingUser(uid, cid, userFollowingId))
|
||||
dispatch(deleteFollowingUser(userFollowingId))
|
||||
}, (error: SocialError) => {
|
||||
dispatch(globalActions.showErrorMessage(error.message))
|
||||
})
|
||||
@@ -109,7 +110,6 @@ export let dbDeleteFollowingUser = (cid: string, userFollowingId: string) => {
|
||||
|
||||
/**
|
||||
* Update a circle from database
|
||||
* @param {Circle} newCircle
|
||||
*/
|
||||
export const dbUpdateCircle = (newCircle: Circle) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
@@ -118,14 +118,13 @@ export const dbUpdateCircle = (newCircle: Circle) => {
|
||||
let uid: string = getState().authorize.uid
|
||||
|
||||
// Write the new data simultaneously in the list
|
||||
let circle: Circle = getState().circle.userCircles[uid][newCircle.id!]
|
||||
let circle: Circle = getState().circle.userTies[uid][newCircle.id!]
|
||||
let updatedCircle: Circle = {
|
||||
name: newCircle.name || circle.name,
|
||||
users: newCircle.users ? newCircle.users : (circle.users || [])
|
||||
name: newCircle.name || circle.name
|
||||
}
|
||||
return circleService.updateCircle(uid,newCircle.id!,circle)
|
||||
return circleService.updateCircle(uid, newCircle.id!, circle)
|
||||
.then(() => {
|
||||
dispatch(updateCircle(uid,{ id: newCircle.id, ...updatedCircle }))
|
||||
dispatch(updateCircle({ id: newCircle.id, ...updatedCircle }))
|
||||
}, (error: SocialError) => {
|
||||
dispatch(globalActions.showErrorMessage(error.message))
|
||||
})
|
||||
@@ -135,17 +134,16 @@ export const dbUpdateCircle = (newCircle: Circle) => {
|
||||
|
||||
/**
|
||||
* Delete a circle from database
|
||||
* @param {string} id is circle identifier
|
||||
*/
|
||||
export const dbDeleteCircle = (id: string) => {
|
||||
export const dbDeleteCircle = (circleId: string) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
|
||||
// Get current user id
|
||||
let uid: string = getState().authorize.uid
|
||||
|
||||
return circleService.deleteCircle(uid,id)
|
||||
return circleService.deleteCircle(uid, circleId)
|
||||
.then(() => {
|
||||
dispatch(deleteCircle(uid, id))
|
||||
dispatch(deleteCircle(circleId))
|
||||
}, (error: SocialError) => {
|
||||
dispatch(globalActions.showErrorMessage(error.message))
|
||||
})
|
||||
@@ -154,7 +152,7 @@ export const dbDeleteCircle = (id: string) => {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all user circles from data base
|
||||
* Get all circles from data base belong to current user
|
||||
*/
|
||||
export const dbGetCircles = () => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
@@ -163,16 +161,7 @@ export const dbGetCircles = () => {
|
||||
|
||||
return circleService.getCircles(uid)
|
||||
.then((circles: { [circleId: string]: Circle }) => {
|
||||
Object.keys(circles).forEach((circleId) => {
|
||||
if (circleId !== '-Followers' && circles[circleId].users) {
|
||||
Object.keys(circles[circleId].users).filter((v, i, a) => a.indexOf(v) === i).forEach((userId) => {
|
||||
dispatch(postActions.dbGetPostsByUserId(userId))
|
||||
dispatch(userActions.dbGetUserInfoByUserId(userId, ''))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
dispatch(addCircles(uid, circles))
|
||||
dispatch(addCircles(circles))
|
||||
})
|
||||
.catch((error: SocialError) => {
|
||||
dispatch(globalActions.showErrorMessage(error.message))
|
||||
@@ -182,6 +171,46 @@ export const dbGetCircles = () => {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all user ties from data base
|
||||
*/
|
||||
export const dbGetUserTies = () => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
let uid: string = getState().authorize.uid
|
||||
if (uid) {
|
||||
userTieService.getUserTies(uid).then((result) => {
|
||||
|
||||
dispatch(userActions.addPeopleInfo(result as any))
|
||||
dispatch(addUserTies(result))
|
||||
|
||||
})
|
||||
.catch((error: SocialError) => {
|
||||
dispatch(globalActions.showErrorMessage(error.message))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all followers
|
||||
*/
|
||||
export const dbGetFollowers = () => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
let uid: string = getState().authorize.uid
|
||||
if (uid) {
|
||||
userTieService.getUserTies(uid).then((result) => {
|
||||
|
||||
dispatch(userActions.addPeopleInfo(result as any))
|
||||
dispatch(addUserTies(result))
|
||||
|
||||
})
|
||||
.catch((error: SocialError) => {
|
||||
dispatch(globalActions.showErrorMessage(error.message))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all user circles from data base by user id
|
||||
* @param uid user identifier
|
||||
@@ -191,12 +220,12 @@ export const dbGetCirclesByUserId = (uid: string) => {
|
||||
|
||||
if (uid) {
|
||||
return circleService.getCircles(uid)
|
||||
.then((circles: { [circleId: string]: Circle }) => {
|
||||
dispatch(addCircles(uid, circles))
|
||||
})
|
||||
.catch((error: SocialError) => {
|
||||
dispatch(globalActions.showErrorMessage(error.message))
|
||||
})
|
||||
.then((circles: { [circleId: string]: Circle }) => {
|
||||
dispatch(addCircles(circles))
|
||||
})
|
||||
.catch((error: SocialError) => {
|
||||
dispatch(globalActions.showErrorMessage(error.message))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -204,9 +233,7 @@ export const dbGetCirclesByUserId = (uid: string) => {
|
||||
/* _____________ CRUD State _____________ */
|
||||
|
||||
/**
|
||||
* Add a normal circle
|
||||
* @param {string} uid is user identifier
|
||||
* @param {Circle} circle
|
||||
* Add a circle
|
||||
*/
|
||||
export const addCircle = (circle: Circle) => {
|
||||
return {
|
||||
@@ -217,37 +244,31 @@ export const addCircle = (circle: Circle) => {
|
||||
|
||||
/**
|
||||
* Update a circle
|
||||
* @param {string} uid is user identifier
|
||||
* @param {Circle} circle
|
||||
*/
|
||||
export const updateCircle = (uid: string, circle: Circle) => {
|
||||
export const updateCircle = (circle: Circle) => {
|
||||
return {
|
||||
type: CircleActionType.UPDATE_CIRCLE,
|
||||
payload: { uid, circle }
|
||||
payload: { circle }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a circle
|
||||
* @param {string} uid is user identifier
|
||||
* @param {string} id is circle identifier
|
||||
*/
|
||||
export const deleteCircle = (uid: string, id: string) => {
|
||||
export const deleteCircle = (circleId: string) => {
|
||||
return {
|
||||
type: CircleActionType.DELETE_CIRCLE,
|
||||
payload: { uid, id }
|
||||
payload: { circleId }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a list of circle
|
||||
* @param {string} uid
|
||||
* @param {circleId: string]: Circle} circles
|
||||
*/
|
||||
export const addCircles = (uid: string, circles: { [circleId: string]: Circle }) => {
|
||||
export const addCircles = (circleList: {[circleId: string]: Circle}) => {
|
||||
return {
|
||||
type: CircleActionType.ADD_LIST_CIRCLE,
|
||||
payload: { uid, circles }
|
||||
payload: { circleList }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,55 +283,126 @@ export const clearAllCircles = () => {
|
||||
|
||||
/**
|
||||
* Open circle settings
|
||||
* @param uid user idenifier
|
||||
* @param id circle identifier
|
||||
*/
|
||||
export const openCircleSettings = (uid: string, id: string) => {
|
||||
export const openCircleSettings = (circleId: string) => {
|
||||
return {
|
||||
type: CircleActionType.OPEN_CIRCLE_SETTINGS,
|
||||
payload: { uid, id }
|
||||
payload: { circleId }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Close open circle settings
|
||||
* @param uid user identifier
|
||||
* @param id circle identifier
|
||||
*/
|
||||
export const closeCircleSettings = (uid: string, id: string) => {
|
||||
export const closeCircleSettings = (circleId: string) => {
|
||||
return {
|
||||
type: CircleActionType.CLOSE_CIRCLE_SETTINGS,
|
||||
payload: { uid, id }
|
||||
payload: { circleId }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add following user in a circle
|
||||
* @param {string} uid user identifire who want to follow the following user
|
||||
* @param {string} cid circle identifier that following user should be added in
|
||||
* @param {string} followingId following user identifier
|
||||
* @param {User} userCircle information about following user
|
||||
* Add following user
|
||||
*/
|
||||
export const addFollowingUser = (uid: string, cid: string, followingId: string, userCircle: User) => {
|
||||
export const addFollowingUser = (userTie: UserTie) => {
|
||||
return {
|
||||
type: CircleActionType.ADD_FOLLOWING_USER,
|
||||
payload: { uid, cid, followingId, userCircle }
|
||||
payload: { userTie }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the user tie
|
||||
*/
|
||||
export const updateUserTie = (userTie: UserTie) => {
|
||||
return {
|
||||
type: CircleActionType.UPDATE_USER_TIE,
|
||||
payload: { userTie }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add user ties
|
||||
*/
|
||||
export const addUserTies = (userTies: {[userId: string]: UserTie }) => {
|
||||
return {
|
||||
type: CircleActionType.ADD_USER_TIE_LIST,
|
||||
payload: { userTies }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add users who send tie request for current user
|
||||
*/
|
||||
export const addUserTieds = (userTieds: {[userId: string]: UserTie }) => {
|
||||
return {
|
||||
type: CircleActionType.ADD_USER_TIED_LIST,
|
||||
payload: { userTieds }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the user from a circle
|
||||
*/
|
||||
export const deleteUserFromCircle = (userId: string, circleId: string) => {
|
||||
return {
|
||||
type: CircleActionType.DELETE_USER_FROM_CIRCLE,
|
||||
payload: { userId, circleId }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete following user
|
||||
*/
|
||||
export const deleteFollowingUser = (userId: string) => {
|
||||
return {
|
||||
type: CircleActionType.DELETE_FOLLOWING_USER,
|
||||
payload: { userId }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the box to select circle
|
||||
*/
|
||||
export const showSelectCircleBox = (userId: string) => {
|
||||
return {
|
||||
type: CircleActionType.SHOW_SELECT_CIRCLE_BOX,
|
||||
payload: { userId }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete following user from a circle
|
||||
* @param {string} uid user identifire who want to follow the following user
|
||||
* @param {string} cid circle identifier that following user should be added in
|
||||
* @param {string} followingId following user identifier
|
||||
* Hide the box to select circle
|
||||
*/
|
||||
export const deleteFollowingUser = (uid: string, cid: string, followingId: string) => {
|
||||
export const hideSelectCircleBox = (userId: string) => {
|
||||
return {
|
||||
type: CircleActionType.DELETE_FOLLOWING_USER,
|
||||
payload: { uid, cid, followingId }
|
||||
type: CircleActionType.HIDE_SELECT_CIRCLE_BOX,
|
||||
payload: { userId }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Show loading on following user
|
||||
*/
|
||||
export const showFollowingUserLoading = (userId: string) => {
|
||||
return {
|
||||
type: CircleActionType.SHOW_FOLLOWING_USER_LOADING,
|
||||
payload: { userId }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide loading on following user
|
||||
*/
|
||||
export const hideFollowingUserLoading = (userId: string) => {
|
||||
return {
|
||||
type: CircleActionType.HIDE_FOLLOWING_USER_LOADING,
|
||||
payload: { userId }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
// - Import react components
|
||||
import moment from 'moment'
|
||||
import _ from 'lodash'
|
||||
|
||||
// - Import domain
|
||||
import { Comment } from 'core/domain/comments'
|
||||
@@ -14,11 +15,14 @@ import * as globalActions from 'actions/globalActions'
|
||||
import * as notifyActions from 'actions/notifyActions'
|
||||
import * as postActions from 'actions/postActions'
|
||||
|
||||
import { IServiceProvider, ServiceProvide } from 'core/factories'
|
||||
import { ICommentService } from 'core/services/comments'
|
||||
import { SocialProviderTypes } from 'core/socialProviderTypes'
|
||||
import { provider } from '../socialEngine'
|
||||
|
||||
const serviceProvider: IServiceProvider = new ServiceProvide()
|
||||
const commentService: ICommentService = serviceProvider.createCommentService()
|
||||
/**
|
||||
* Get service providers
|
||||
*/
|
||||
const commentService: ICommentService = provider.get<ICommentService>(SocialProviderTypes.CommentService)
|
||||
|
||||
/* _____________ CRUD DB _____________ */
|
||||
|
||||
@@ -28,11 +32,12 @@ const commentService: ICommentService = serviceProvider.createCommentService()
|
||||
* @param {object} newComment user comment
|
||||
* @param {function} callBack will be fired when server responsed
|
||||
*/
|
||||
export const dbAddComment = (ownerPostUserId: string | null,newComment: Comment, callBack: Function) => {
|
||||
export const dbAddComment = (ownerPostUserId: string, newComment: Comment, callBack: Function) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
|
||||
dispatch(globalActions.showTopLoading())
|
||||
|
||||
const state = getState()
|
||||
let uid: string = getState().authorize.uid
|
||||
|
||||
let comment: Comment = {
|
||||
@@ -74,8 +79,10 @@ export const dbAddComment = (ownerPostUserId: string | null,newComment: Comment,
|
||||
*/
|
||||
export const dbGetComments = (ownerUserId: string, postId: string) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
const state = getState()
|
||||
let uid: string = getState().authorize.uid
|
||||
if (uid) {
|
||||
|
||||
return commentService.getComments(postId, (comments: {[postId: string]: {[commentId: string]: Comment}}) => {
|
||||
|
||||
/**
|
||||
@@ -89,24 +96,21 @@ export const dbGetComments = (ownerUserId: string, postId: string) => {
|
||||
return
|
||||
}
|
||||
|
||||
if (comments && Object.keys(comments).length > 0) {
|
||||
commentsCount = Object.keys(comments).length
|
||||
let sortedObjects = comments as any
|
||||
const desiredComments = comments[postId]
|
||||
if (desiredComments && Object.keys(desiredComments).length > 0) {
|
||||
commentsCount = Object.keys(desiredComments).length
|
||||
let sortedObjects = desiredComments as any
|
||||
// Sort posts with creation date
|
||||
sortedObjects.sort((a: any, b: any) => {
|
||||
return parseInt(b.creationDate, 10) - parseInt(a.creationDate, 10)
|
||||
})
|
||||
if (!post.comments) {
|
||||
post.comments = {}
|
||||
}
|
||||
Object.keys(sortedObjects).slice(0, 3).forEach((commentId) => {
|
||||
post.comments![commentId] = {
|
||||
id: commentId,
|
||||
...sortedObjects[commentId]
|
||||
}
|
||||
})
|
||||
|
||||
dispatch(postActions.updatePost(post.ownerUserId!,post))
|
||||
const commentKeys = Object.keys(sortedObjects)
|
||||
if (commentKeys.length > 1) {
|
||||
sortedObjects = _.fromPairs(_.toPairs(sortedObjects)
|
||||
.sort((a: any, b: any) => parseInt(b[1].creationDate,10) - parseInt(a[1].creationDate,10)).slice(0, 3))
|
||||
|
||||
}
|
||||
post.comments = sortedObjects
|
||||
post.commentCounter = commentsCount
|
||||
dispatch(postActions.updatePost(post))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -119,29 +123,17 @@ export const dbGetComments = (ownerUserId: string, postId: string) => {
|
||||
* @param {string} postId is the identifier of the post which comment belong to
|
||||
* @param {string} text is the text of comment
|
||||
*/
|
||||
export const dbUpdateComment = (id: string, postId: string, text: string) => {
|
||||
export const dbUpdateComment = (comment: Comment) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
|
||||
delete comment.editorStatus
|
||||
dispatch(globalActions.showTopLoading())
|
||||
|
||||
// Get current user id
|
||||
let uid: string = getState().authorize.uid
|
||||
|
||||
// Write the new data simultaneously in the list
|
||||
let comment: Comment = getState().comment.postComments[postId][id]
|
||||
let updatedComment: Comment = {
|
||||
postId: postId,
|
||||
score: comment.score,
|
||||
text: text,
|
||||
creationDate: comment.creationDate,
|
||||
userDisplayName: comment.userDisplayName,
|
||||
userAvatar: comment.userAvatar,
|
||||
userId: uid
|
||||
}
|
||||
|
||||
return commentService.updateComment(updatedComment)
|
||||
return commentService.updateComment(comment)
|
||||
.then(() => {
|
||||
dispatch(updateComment( id, postId, text))
|
||||
dispatch(updateComment( comment))
|
||||
dispatch(globalActions.hideTopLoading())
|
||||
|
||||
}, (error: SocialError) => {
|
||||
@@ -168,7 +160,7 @@ export const dbDeleteComment = (id?: string | null, postId?: string) => {
|
||||
// Get current user id
|
||||
let uid: string = getState().authorize.uid
|
||||
|
||||
return commentService.deleteComment(id!,postId!)
|
||||
return commentService.deleteComment(id!)
|
||||
.then(() => {
|
||||
dispatch(deleteComment(id!, postId!))
|
||||
dispatch(globalActions.hideTopLoading())
|
||||
@@ -202,11 +194,11 @@ export const addComment = (comment: Comment) => {
|
||||
* @param postId post identefier which comment belong to
|
||||
* @param text the new text for comment
|
||||
*/
|
||||
export const updateComment = ( id: string, postId: string, text: string) => {
|
||||
export const updateComment = ( comment: Comment) => {
|
||||
|
||||
return {
|
||||
type: CommentActionType.UPDATE_COMMENT,
|
||||
payload: {id, postId, text}
|
||||
payload: { comment }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,23 @@ export const hideMessage = () => {
|
||||
* @param {string} message
|
||||
*/
|
||||
export const showErrorMessage = (message: string) => {
|
||||
const appElement = document.getElementById('app')
|
||||
const masterElement = document.getElementById('master')
|
||||
const container = document.createElement('div')
|
||||
const div = document.createElement('div')
|
||||
div.innerHTML = message
|
||||
container.style.position = '100000'
|
||||
container.style.position = 'fixed'
|
||||
container.style.backgroundColor = '#32c3e4b8'
|
||||
container.style.width = '100%'
|
||||
container.style.height = '100%'
|
||||
container.style.display = 'flex'
|
||||
container.style.alignItems = 'center'
|
||||
container.style.alignItems = 'center'
|
||||
container.style.flexDirection = 'row'
|
||||
container.appendChild(div)
|
||||
|
||||
appElement!.insertBefore(container, masterElement)
|
||||
return {
|
||||
type: GlobalActionType.SHOW_ERROR_MESSAGE_GLOBAL,
|
||||
payload: message
|
||||
|
||||
@@ -15,13 +15,16 @@ import * as globalActions from 'actions/globalActions'
|
||||
// - Import app API
|
||||
import FileAPI from 'api/FileAPI'
|
||||
|
||||
import { IServiceProvider, ServiceProvide } from 'core/factories'
|
||||
import { IImageGalleryService } from 'core/services/imageGallery'
|
||||
import { FileResult } from 'models/files/fileResult'
|
||||
import { SocialProviderTypes } from 'core/socialProviderTypes'
|
||||
import { provider } from '../socialEngine'
|
||||
|
||||
const serviceProvider: IServiceProvider = new ServiceProvide()
|
||||
const imageGalleryService: IImageGalleryService = serviceProvider.createImageGalleryService()
|
||||
const storageService: IStorageService = serviceProvider.createStorageService()
|
||||
/**
|
||||
* Get service providers
|
||||
*/
|
||||
const imageGalleryService: IImageGalleryService = provider.get<IImageGalleryService>(SocialProviderTypes.ImageGalleryService)
|
||||
const storageService: IStorageService = provider.get<IStorageService>(SocialProviderTypes.StorageService)
|
||||
|
||||
/* _____________ UI Actions _____________ */
|
||||
|
||||
|
||||
@@ -12,11 +12,14 @@ import { NotificationActionType } from 'constants/notificationActionType'
|
||||
import * as globalActions from 'actions/globalActions'
|
||||
import * as userActions from 'actions/userActions'
|
||||
|
||||
import { IServiceProvider, ServiceProvide } from 'core/factories'
|
||||
import { INotificationService } from 'core/services/notifications'
|
||||
import { SocialProviderTypes } from 'core/socialProviderTypes'
|
||||
import { provider } from '../socialEngine'
|
||||
|
||||
const serviceProvider: IServiceProvider = new ServiceProvide()
|
||||
const notificationService: INotificationService = serviceProvider.createNotificationService()
|
||||
/**
|
||||
* Get service providers
|
||||
*/
|
||||
const notificationService: INotificationService = provider.get<INotificationService>(SocialProviderTypes.NotificationService)
|
||||
|
||||
/* _____________ CRUD DB _____________ */
|
||||
|
||||
|
||||
@@ -15,11 +15,14 @@ import { PostActionType } from 'constants/postActionType'
|
||||
// - Import actions
|
||||
import * as globalActions from 'actions/globalActions'
|
||||
|
||||
import { IServiceProvider, ServiceProvide } from 'core/factories'
|
||||
import { IPostService } from 'core/services/posts'
|
||||
import { SocialProviderTypes } from 'core/socialProviderTypes'
|
||||
import { provider } from '../socialEngine'
|
||||
|
||||
const serviceProvider: IServiceProvider = new ServiceProvide()
|
||||
const postService: IPostService = serviceProvider.createPostService()
|
||||
/**
|
||||
* Get service providers
|
||||
*/
|
||||
const postService: IPostService = provider.get<IPostService>(SocialProviderTypes.PostService)
|
||||
|
||||
/* _____________ CRUD DB _____________ */
|
||||
|
||||
@@ -127,7 +130,7 @@ export const dbUpdatePost = (updatedPost: Post, callBack: Function) => {
|
||||
|
||||
return postService.updatePost(updatedPost).then(() => {
|
||||
|
||||
dispatch(updatePost(uid, { ...updatedPost }))
|
||||
dispatch(updatePost(updatedPost))
|
||||
callBack()
|
||||
dispatch(globalActions.hideTopLoading())
|
||||
|
||||
@@ -169,13 +172,88 @@ export const dbDeletePost = (id: string) => {
|
||||
/**
|
||||
* Get all user posts from data base
|
||||
*/
|
||||
export const dbGetPosts = () => {
|
||||
export const dbGetPosts = (page: number = 0, limit: number = 10) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
let uid: string = getState().authorize.uid
|
||||
if (uid) {
|
||||
const state = getState()
|
||||
const {stream} = state.post
|
||||
const lastPageRequest = stream.lastPageRequest
|
||||
const lastPostId = stream.lastPostId
|
||||
const hasMoreData = stream.hasMoreData
|
||||
|
||||
return postService.getPosts(uid).then((posts: { [postId: string]: Post }) => {
|
||||
dispatch(addPosts(uid, posts))
|
||||
let uid: string = state.authorize.uid
|
||||
if (uid && lastPageRequest !== page) {
|
||||
return postService.getPosts(uid, lastPostId, page, limit).then((result) => {
|
||||
if (!result.posts || !(result.posts.length > 0)) {
|
||||
return dispatch(notMoreDataStream())
|
||||
}
|
||||
|
||||
// Store last post Id
|
||||
dispatch(lastPostStream(result.newLastPostId))
|
||||
|
||||
let parsedData: { [userId: string]: {[postId: string]: Post} } = {}
|
||||
result.posts.forEach((post) => {
|
||||
const postId = Object.keys(post)[0]
|
||||
const postData = post[postId]
|
||||
const ownerId = postData.ownerUserId!
|
||||
parsedData = {
|
||||
...parsedData,
|
||||
[ownerId]: {
|
||||
...parsedData[ownerId],
|
||||
[postId]: {
|
||||
...postData
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
dispatch(addPosts(parsedData))
|
||||
})
|
||||
.catch((error: SocialError) => {
|
||||
dispatch(globalActions.showErrorMessage(error.message))
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all user posts from data base
|
||||
*/
|
||||
export const dbGetPostsByUserId = (page: number = 0, limit: number = 10) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
const state = getState()
|
||||
const {profile} = state.post
|
||||
const lastPageRequest = profile.lastPageRequest
|
||||
const lastPostId = profile.lastPostId
|
||||
const hasMoreData = profile.hasMoreData
|
||||
|
||||
let uid: string = state.authorize.uid
|
||||
|
||||
if (uid && lastPageRequest !== page) {
|
||||
|
||||
return postService.getPostsByUserId(uid, lastPostId, page, limit).then((result) => {
|
||||
|
||||
if (!result.posts || !(result.posts.length > 0)) {
|
||||
return dispatch(notMoreDataProfile())
|
||||
}
|
||||
// Store last post Id
|
||||
dispatch(lastPostProfile(result.newLastPostId))
|
||||
|
||||
let parsedData: { [userId: string]: {[postId: string]: Post} } = {}
|
||||
result.posts.forEach((post) => {
|
||||
const postId = Object.keys(post)[0]
|
||||
const postData = post[postId]
|
||||
const ownerId = postData.ownerUserId!
|
||||
parsedData = {
|
||||
...parsedData,
|
||||
[ownerId]: {
|
||||
...parsedData[ownerId],
|
||||
[postId]: {
|
||||
...postData
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
dispatch(addPosts(parsedData))
|
||||
})
|
||||
.catch((error: SocialError) => {
|
||||
dispatch(globalActions.showErrorMessage(error.message))
|
||||
@@ -205,22 +283,6 @@ export const dbGetPostById = (uid: string, postId: string) => {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all user posts from data base by user id
|
||||
* @param uid posts owner identifier
|
||||
*/
|
||||
export const dbGetPostsByUserId = (uid: string) => {
|
||||
return (dispatch: Function, getState: Function) => {
|
||||
|
||||
if (uid) {
|
||||
return postService.getPosts(uid).then((posts: { [postId: string]: Post }) => {
|
||||
dispatch(addPosts(uid, posts))
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* _____________ CRUD State _____________ */
|
||||
|
||||
/**
|
||||
@@ -240,10 +302,10 @@ export const addPost = (uid: string, post: Post) => {
|
||||
* @param {string} uid is user identifier
|
||||
* @param {Post} post
|
||||
*/
|
||||
export const updatePost = (uid: string, post: Post) => {
|
||||
export const updatePost = (post: Post) => {
|
||||
return {
|
||||
type: PostActionType.UPDATE_POST,
|
||||
payload: { uid, post }
|
||||
payload: { post }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,10 +326,10 @@ export const deletePost = (uid: string, id: string) => {
|
||||
* @param {string} uid
|
||||
* @param {[object]} posts
|
||||
*/
|
||||
export const addPosts = (uid: string, posts: { [postId: string]: Post }) => {
|
||||
export const addPosts = (userPosts: { [userId: string]: {[postId: string]: Post} }) => {
|
||||
return {
|
||||
type: PostActionType.ADD_LIST_POST,
|
||||
payload: { uid, posts }
|
||||
payload: { userPosts }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,7 +344,6 @@ export const clearAllData = () => {
|
||||
|
||||
/**
|
||||
* Add a post with image
|
||||
* @param {object} post
|
||||
*/
|
||||
export const addImagePost = (uid: string, post: any) => {
|
||||
return {
|
||||
@@ -291,3 +352,88 @@ export const addImagePost = (uid: string, post: any) => {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set stream has more data to show
|
||||
*/
|
||||
export const hasMoreDataStream = () => {
|
||||
return {
|
||||
type: PostActionType.HAS_MORE_DATA_STREAM
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set stream has not data any more to show
|
||||
*/
|
||||
export const notMoreDataStream = () => {
|
||||
return {
|
||||
type: PostActionType.NOT_MORE_DATA_STREAM
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set last page request of stream
|
||||
*/
|
||||
export const requestPageStream = (page: number) => {
|
||||
return {
|
||||
type: PostActionType.REQUEST_PAGE_STREAM,
|
||||
payload: { page}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set last post identification of stream
|
||||
*/
|
||||
export const lastPostStream = (lastPostId: string) => {
|
||||
return {
|
||||
type: PostActionType.LAST_POST_STREAM,
|
||||
payload: { lastPostId}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set profile posts has more data to show
|
||||
*/
|
||||
export const hasMoreDataProfile = () => {
|
||||
return {
|
||||
type: PostActionType.HAS_MORE_DATA_PROFILE
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set profile posts has not data any more to show
|
||||
*/
|
||||
export const notMoreDataProfile = () => {
|
||||
return {
|
||||
type: PostActionType.NOT_MORE_DATA_PROFILE
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set last page request of profile posts
|
||||
*/
|
||||
export const requestPageProfile = (page: number) => {
|
||||
return {
|
||||
type: PostActionType.REQUEST_PAGE_PROFILE,
|
||||
payload: { page}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set last post identification of profile posts
|
||||
*/
|
||||
export const lastPostProfile = (lastPostId: string) => {
|
||||
return {
|
||||
type: PostActionType.LAST_POST_PROFILE,
|
||||
payload: { lastPostId}
|
||||
}
|
||||
|
||||
}
|
||||
51
src/actions/serveActions.ts
Normal file
51
src/actions/serveActions.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import moment from 'moment'
|
||||
|
||||
// - Import action types
|
||||
import { ServerActionType } from 'constants/serverActionType'
|
||||
|
||||
// - Import domain
|
||||
|
||||
// - Import actions
|
||||
import * as globalActions from 'actions/globalActions'
|
||||
import { ServerRequestModel } from 'models/server/serverRequestModel'
|
||||
import { SocialError } from 'core/domain/common/socialError'
|
||||
|
||||
/**
|
||||
* Add a request
|
||||
* @param {Request} request
|
||||
*/
|
||||
export const sendRequest = (request: ServerRequestModel) => {
|
||||
return { type: ServerActionType.ADD_REQUEST, payload: request }
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* delete a request
|
||||
*/
|
||||
export const deleteRequest = (requestId: string) => {
|
||||
return { type: ServerActionType.DELETE_REQUEST, payload: {requestId} }
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Update request stattus ti successful
|
||||
*/
|
||||
export const okRequest = (requestId: string) => {
|
||||
return { type: ServerActionType.OK_REQUEST, payload: {requestId} }
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set error request
|
||||
*/
|
||||
export const errorRequest = (requestId: string, error: SocialError) => {
|
||||
return { type: ServerActionType.ERROR_REQUEST, payload: {requestId, error} }
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all data
|
||||
*/
|
||||
export const clearAllrequests = () => {
|
||||
return { type: ServerActionType.CLEAR_ALL_DATA_REQUEST }
|
||||
}
|
||||
5
src/actions/serverRequestStatusType.ts
Normal file
5
src/actions/serverRequestStatusType.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export enum ServerRequestStatusType {
|
||||
Sent = 'Sent',
|
||||
OK = 'OK',
|
||||
Error = 'Error'
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
// - Import react components
|
||||
import { provider } from '../socialEngine'
|
||||
import _ from 'lodash'
|
||||
// - Import domain
|
||||
import { Profile } from 'core/domain/users'
|
||||
@@ -11,11 +12,13 @@ import { UserActionType } from 'constants/userActionType'
|
||||
import * as globalActions from 'actions/globalActions'
|
||||
import * as userActions from 'actions/userActions'
|
||||
|
||||
import { IServiceProvider, ServiceProvide } from 'core/factories'
|
||||
import { IUserService } from 'core/services/users'
|
||||
import { SocialProviderTypes } from 'core/socialProviderTypes'
|
||||
|
||||
const serviceProvider: IServiceProvider = new ServiceProvide()
|
||||
const userService: IUserService = serviceProvider.createUserService()
|
||||
/**
|
||||
* Get service providers
|
||||
*/
|
||||
const userService: IUserService = provider.get<IUserService>(SocialProviderTypes.UserService)
|
||||
|
||||
/* _____________ CRUD DB _____________ */
|
||||
|
||||
@@ -93,7 +96,7 @@ export const dbUpdateUserInfo = (newProfile: Profile) => {
|
||||
let uid: string = getState().authorize.uid
|
||||
|
||||
let profile: Profile = getState().user.info[uid]
|
||||
let updatedProfie: Profile = {
|
||||
let updatedProfile: Profile = {
|
||||
avatar: newProfile.avatar || profile.avatar || '',
|
||||
banner: newProfile.banner || profile.banner || 'https://firebasestorage.googleapis.com/v0/b/open-social-33d92.appspot.com/o/images%2F751145a1-9488-46fd-a97e-04018665a6d3.JPG?alt=media&token=1a1d5e21-5101-450e-9054-ea4a20e06c57',
|
||||
email: newProfile.email || profile.email || '',
|
||||
@@ -101,10 +104,9 @@ export const dbUpdateUserInfo = (newProfile: Profile) => {
|
||||
tagLine: newProfile.tagLine || profile.tagLine || '',
|
||||
creationDate: newProfile.creationDate
|
||||
}
|
||||
return userService.updateUserProfile(uid,updatedProfile).then(() => {
|
||||
|
||||
return userService.updateUserProfile(uid,updatedProfie).then(() => {
|
||||
|
||||
dispatch(updateUserInfo(uid, updatedProfie))
|
||||
dispatch(updateUserInfo(uid, updatedProfile))
|
||||
dispatch(closeEditProfile())
|
||||
})
|
||||
.catch((error: SocialError) => dispatch(globalActions.showErrorMessage(error.message)))
|
||||
@@ -114,17 +116,40 @@ export const dbUpdateUserInfo = (newProfile: Profile) => {
|
||||
}
|
||||
|
||||
// - Get people info from database
|
||||
export const dbGetPeopleInfo = (page?: number) => {
|
||||
export const dbGetPeopleInfo = (page: number, limit: number) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
const {authorize, user} = getState()
|
||||
let uid: string = authorize.uid
|
||||
if (uid) {
|
||||
const lastKey = ''
|
||||
return userService.getUsersProfile(uid, lastKey)
|
||||
.then((usersProfile: {[userId: string]: Profile}) => {
|
||||
dispatch(addPeopleInfo(usersProfile))
|
||||
const state = getState()
|
||||
const {people} = state.user
|
||||
const lastPageRequest = people.lastPageRequest
|
||||
const lastUserId = people.lastUserId
|
||||
const hasMoreData = people.hasMoreData
|
||||
|
||||
let uid: string = state.authorize.uid
|
||||
|
||||
if (uid && lastPageRequest !== page) {
|
||||
|
||||
return userService.getUsersProfile(uid, lastUserId, page, limit).then((result) => {
|
||||
|
||||
if (!result.users || !(result.users.length > 0)) {
|
||||
return dispatch(notMoreDataPeople())
|
||||
}
|
||||
// Store last user Id
|
||||
dispatch(lastUserPeople(result.newLastUserId))
|
||||
|
||||
let parsedData: {[userId: string]: Profile} = {}
|
||||
result.users.forEach((post) => {
|
||||
const userId = Object.keys(post)[0]
|
||||
const postData = post[userId]
|
||||
parsedData = {
|
||||
...parsedData,
|
||||
[userId]: {
|
||||
...postData
|
||||
}
|
||||
}
|
||||
})
|
||||
dispatch(addPeopleInfo(parsedData))
|
||||
})
|
||||
.catch((error: SocialError) => dispatch(globalActions.showErrorMessage(error.message)))
|
||||
.catch((error: SocialError) => dispatch(globalActions.showErrorMessage(error.message)))
|
||||
|
||||
}
|
||||
}
|
||||
@@ -167,17 +192,6 @@ export const updateUserInfo = (uid: string, info: Profile) => {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* User info
|
||||
* @param {Profile} info
|
||||
*/
|
||||
export const userInfo = (info: Profile) => {
|
||||
return {
|
||||
type: UserActionType.USER_INFO,
|
||||
info
|
||||
}
|
||||
}
|
||||
|
||||
export const clearAllData = () => {
|
||||
return {
|
||||
type: UserActionType.CLEAR_ALL_DATA_USER
|
||||
@@ -202,4 +216,46 @@ export const closeEditProfile = () => {
|
||||
type: UserActionType.CLOSE_EDIT_PROFILE
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set profile posts has more data to show
|
||||
*/
|
||||
export const hasMoreDataPeople = () => {
|
||||
return {
|
||||
type: UserActionType.HAS_MORE_DATA_PEOPLE
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set profile posts has not data any more to show
|
||||
*/
|
||||
export const notMoreDataPeople = () => {
|
||||
return {
|
||||
type: UserActionType.NOT_MORE_DATA_PEOPLE
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set last page request of profile posts
|
||||
*/
|
||||
export const requestPagePeople = (page: number) => {
|
||||
return {
|
||||
type: UserActionType.REQUEST_PAGE_PEOPLE,
|
||||
payload: { page}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set last user identification of find people page
|
||||
*/
|
||||
export const lastUserPeople = (lastUserId: string) => {
|
||||
return {
|
||||
type: UserActionType.LAST_USER_PEOPLE,
|
||||
payload: { lastUserId}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,12 +11,15 @@ import * as globalActions from 'actions/globalActions'
|
||||
import * as notifyActions from 'actions/notifyActions'
|
||||
import * as postActions from 'actions/postActions'
|
||||
|
||||
import { IServiceProvider, ServiceProvide } from 'core/factories'
|
||||
import { IVoteService } from 'core/services/votes'
|
||||
import { Post } from 'core/domain/posts'
|
||||
import { SocialProviderTypes } from 'core/socialProviderTypes'
|
||||
import { provider } from '../socialEngine'
|
||||
|
||||
const serviceProvider: IServiceProvider = new ServiceProvide()
|
||||
const voteService: IVoteService = serviceProvider.createVoteService()
|
||||
/**
|
||||
* Get service providers
|
||||
*/
|
||||
const voteService: IVoteService = provider.get<IVoteService>(SocialProviderTypes.VoteService)
|
||||
|
||||
/* _____________ CRUD DB _____________ */
|
||||
|
||||
@@ -40,7 +43,8 @@ export const dbAddVote = (postId: string,ownerPostUserId: string) => {
|
||||
const post: Post = state.post.userPosts[ownerPostUserId][postId]
|
||||
|
||||
post.score! += 1
|
||||
dispatch(postActions.updatePost(ownerPostUserId,post))
|
||||
post.votes = { ...post.votes!, [uid]: true}
|
||||
dispatch(postActions.updatePost(post))
|
||||
|
||||
return voteService.addVote(vote).then((voteKey: string) => {
|
||||
if (uid !== ownerPostUserId) {
|
||||
@@ -56,7 +60,8 @@ export const dbAddVote = (postId: string,ownerPostUserId: string) => {
|
||||
})
|
||||
.catch((error) => {
|
||||
post.score! -= 1
|
||||
dispatch(postActions.updatePost(ownerPostUserId,post))
|
||||
post.votes = { ...post.votes!, [uid]: false}
|
||||
dispatch(postActions.updatePost(post))
|
||||
dispatch(globalActions.showErrorMessage(error.message))
|
||||
})
|
||||
}
|
||||
@@ -99,17 +104,15 @@ export const dbDeleteVote = (postId: string, ownerPostUserId: string) => {
|
||||
const state = getState()
|
||||
// Get current user id
|
||||
let uid: string = state.authorize.uid
|
||||
|
||||
let votes: {[voteId: string]: Vote} = getState().vote.postVotes[postId]
|
||||
let id: string = Object.keys(votes).filter((key) => votes[key].userId === uid)[0]
|
||||
const vote = votes[id]
|
||||
const post: Post = state.post.userPosts[ownerPostUserId][postId]
|
||||
post.score! -= 1
|
||||
dispatch(postActions.updatePost(ownerPostUserId,post))
|
||||
return voteService.deleteVote(vote).then(x => x)
|
||||
post.votes = { ...post.votes!, [uid]: false}
|
||||
dispatch(postActions.updatePost(post))
|
||||
return voteService.deleteVote(uid, postId).then(x => x)
|
||||
.catch((error: any) => {
|
||||
post.score! += 1
|
||||
dispatch(postActions.updatePost(ownerPostUserId,post))
|
||||
post.votes = { ...post.votes!, [uid]: true}
|
||||
dispatch(postActions.updatePost(post))
|
||||
dispatch(globalActions.showErrorMessage(error.message))
|
||||
})
|
||||
}
|
||||
@@ -129,8 +132,8 @@ export const addVote = (vote: Vote) => {
|
||||
* @param {string} id vote identifier
|
||||
* @param {string} postId post identifier which vote on
|
||||
*/
|
||||
export const deleteVote = (id: string, postId: string) => {
|
||||
return { type: VoteActionType.DELETE_VOTE, payload: {id, postId} }
|
||||
export const deleteVote = (userId: string, postId: string) => {
|
||||
return { type: VoteActionType.DELETE_VOTE, payload: {userId, postId} }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Circle, UserFollower } from 'core/domain/circles'
|
||||
import { Circle, UserTie } from 'core/domain/circles'
|
||||
|
||||
/**
|
||||
* Get the circles' id which the specify users is in that circle
|
||||
@@ -24,7 +24,7 @@ export const getUserBelongCircles = (circles: {[circleId: string]: Circle},follo
|
||||
* @param {object} circles
|
||||
*/
|
||||
export const getFollowingUsers = (circles: {[circleId: string]: Circle}) => {
|
||||
let followingUsers: {[userId: string]: UserFollower} = {}
|
||||
let followingUsers: {[userId: string]: UserTie} = {}
|
||||
Object.keys(circles).forEach((cid) => {
|
||||
if (cid.trim() !== '-Followers' && circles[cid].users) {
|
||||
Object.keys(circles[cid].users).forEach((userId) => {
|
||||
|
||||
32
src/api/CommonAPI.ts
Normal file
32
src/api/CommonAPI.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Log the data
|
||||
* @param title log title
|
||||
* @param data log data object
|
||||
*/
|
||||
const logger = (title: string, data: any, trace?: boolean) => {
|
||||
const randomColor = getRandomColor()
|
||||
if (trace) {
|
||||
console.trace()
|
||||
}
|
||||
console.log(`\n\n\n%c ${title} :\n`, `color:${getRandomColor()};font-size:15`)
|
||||
console.log('%c =========================================', `color:${randomColor}`)
|
||||
console.log(data)
|
||||
console.log('%c =========================================', `color:${randomColor}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get random color in hex
|
||||
*/
|
||||
const getRandomColor = () => {
|
||||
let letters = '0123456789ABCDEF'
|
||||
let color = '#'
|
||||
for (let i = 0; i < 6; i++) {
|
||||
color += letters[Math.floor(Math.random() * 16)]
|
||||
}
|
||||
return color
|
||||
}
|
||||
|
||||
export default {
|
||||
logger,
|
||||
getRandomColor
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import { ServerRequestType } from 'constants/serverRequestType'
|
||||
|
||||
// - Import actions
|
||||
|
||||
const isValidEmail = (email: string) => {
|
||||
@@ -5,6 +7,10 @@ const isValidEmail = (email: string) => {
|
||||
return re.test(email)
|
||||
}
|
||||
|
||||
const createServerRequestId = (requestType: ServerRequestType, uniqueId: string) => {
|
||||
return `${requestType}:${uniqueId}`
|
||||
}
|
||||
|
||||
function queryString (name: string, url: string = window.location.href) {
|
||||
name = name.replace(/[[]]/g, '\\$&')
|
||||
|
||||
@@ -23,5 +29,6 @@ function queryString (name: string, url: string = window.location.href) {
|
||||
|
||||
export default {
|
||||
isValidEmail,
|
||||
queryString
|
||||
queryString,
|
||||
createServerRequestId
|
||||
}
|
||||
|
||||
@@ -244,8 +244,8 @@ const mapDispatchToProps = (dispatch: any, ownProps: ICircleComponentProps) => {
|
||||
return {
|
||||
deleteCircle: (id: string) => dispatch(circleActions.dbDeleteCircle(id)),
|
||||
updateCircle: (circle: Circle) => dispatch(circleActions.dbUpdateCircle(circle)),
|
||||
closeCircleSettings: () => dispatch(circleActions.closeCircleSettings(uid, ownProps.id)),
|
||||
openCircleSettings: () => dispatch(circleActions.openCircleSettings(uid, ownProps.id)),
|
||||
closeCircleSettings: () => dispatch(circleActions.closeCircleSettings(ownProps.id)),
|
||||
openCircleSettings: () => dispatch(circleActions.openCircleSettings(ownProps.id)),
|
||||
goTo: (url: string) => dispatch(push(url))
|
||||
|
||||
}
|
||||
@@ -258,9 +258,12 @@ const mapDispatchToProps = (dispatch: any, ownProps: ICircleComponentProps) => {
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: ICircleComponentProps) => {
|
||||
let { uid } = state.authorize
|
||||
const {circle, authorize, server} = state
|
||||
const { uid } = state.authorize
|
||||
const circles: { [circleId: string]: Circle } = circle ? (circle.circleList || {}) : {}
|
||||
const currentCircle = (circles ? circles[ownProps.id] : {}) as Circle
|
||||
return {
|
||||
openSetting: state.circle ? (state.circle.userCircles[uid] ? (state.circle.userCircles[uid][ownProps.id].openCircleSettings || false) : false) : false,
|
||||
openSetting: state.circle ? (currentCircle ? (currentCircle.openCircleSettings || false) : false) : false,
|
||||
userInfo: state.user.info
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import PropTypes from 'prop-types'
|
||||
import moment from 'moment'
|
||||
import Linkify from 'react-linkify'
|
||||
|
||||
import { Comment } from 'core/domain/comments'
|
||||
|
||||
// - Import material UI libraries
|
||||
import { List, ListItem } from 'material-ui/List'
|
||||
import Divider from 'material-ui/Divider'
|
||||
@@ -183,8 +185,10 @@ export class CommentComponent extends Component<ICommentComponentProps,ICommentC
|
||||
* @param {event} evt is an event passed by clicking on post button
|
||||
*/
|
||||
handleUpdateComment = (evt: any) => {
|
||||
|
||||
this.props.update(this.props.comment.id, this.props.comment.postId, this.state.text)
|
||||
const {comment} = this.props
|
||||
comment.editorStatus = undefined
|
||||
comment.text = this.state.text
|
||||
this.props.update(comment)
|
||||
this.setState({
|
||||
initialText: this.state.text
|
||||
})
|
||||
@@ -302,13 +306,18 @@ export class CommentComponent extends Component<ICommentComponentProps,ICommentC
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapDispatchToProps = (dispatch: any, ownProps: any) => {
|
||||
const mapDispatchToProps = (dispatch: any, ownProps: ICommentComponentProps) => {
|
||||
return {
|
||||
delete: (id: string| null, postId: string) => dispatch(commentActions.dbDeleteComment(id, postId)),
|
||||
update: (id: string, postId: string, comment: string) => dispatch(commentActions.dbUpdateComment(id, postId, comment)),
|
||||
update: (comment: Comment) => {
|
||||
console.log('====================================')
|
||||
console.log(comment)
|
||||
console.log('====================================')
|
||||
dispatch(commentActions.dbUpdateComment(comment))
|
||||
},
|
||||
openEditor: () => dispatch(commentActions.openCommentEditor({ id: ownProps.comment.id, postId: ownProps.comment.postId })),
|
||||
closeEditor: () => dispatch(commentActions.closeCommentEditor({ id: ownProps.comment.id, postId: ownProps.comment.postId })),
|
||||
getUserInfo: () => dispatch(userActions.dbGetUserInfoByUserId(ownProps.comment.userId,''))
|
||||
getUserInfo: () => dispatch(userActions.dbGetUserInfoByUserId(ownProps.comment.userId!,''))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ export interface ICommentComponentProps {
|
||||
*
|
||||
* @memberof ICommentComponentProps
|
||||
*/
|
||||
update: (id?: string | null, postId?: string, comment?: string | null) => any
|
||||
update: (comment: Comment) => any
|
||||
|
||||
/**
|
||||
* Delete comment
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// - Import react components
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import _ from 'lodash'
|
||||
import { connect } from 'react-redux'
|
||||
import Paper from 'material-ui/Paper'
|
||||
import FlatButton from 'material-ui/FlatButton'
|
||||
@@ -101,7 +102,7 @@ export class CommentGroupComponent extends Component<ICommentGroupComponentProps
|
||||
clearCommentWrite = () => {
|
||||
this.setState({
|
||||
commentText: '',
|
||||
postDisable: false
|
||||
postDisable: true
|
||||
})
|
||||
}
|
||||
|
||||
@@ -109,7 +110,10 @@ export class CommentGroupComponent extends Component<ICommentGroupComponentProps
|
||||
* Post comment
|
||||
*/
|
||||
handlePostComment = () => {
|
||||
|
||||
this.props.send!(this.state.commentText, this.props.postId, this.clearCommentWrite)
|
||||
|
||||
this.clearCommentWrite()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,9 +144,10 @@ export class CommentGroupComponent extends Component<ICommentGroupComponentProps
|
||||
commentList = () => {
|
||||
let comments = this.props.commentSlides
|
||||
if (comments) {
|
||||
|
||||
comments = _.fromPairs(_.toPairs(comments)
|
||||
.sort((a: any, b: any) => parseInt(b[1].creationDate,10) - parseInt(a[1].creationDate,10)))
|
||||
let parsedComments: Comment[] = []
|
||||
Object.keys(comments).slice(0, 3).forEach((commentId) => {
|
||||
Object.keys(comments).forEach((commentId) => {
|
||||
parsedComments.push({
|
||||
id: commentId,
|
||||
...comments![commentId]
|
||||
@@ -222,6 +227,7 @@ export class CommentGroupComponent extends Component<ICommentGroupComponentProps
|
||||
<FlatButton primary={true} disabled={this.state.postDisable} label='Post' style={{ float: 'right', clear: 'both', zIndex: 5, margin: '0px 5px 5px 0px', fontWeight: 400 }} onClick={this.handlePostComment} />
|
||||
</Paper>
|
||||
</div>)
|
||||
|
||||
/**
|
||||
* Return Elements
|
||||
*/
|
||||
|
||||
@@ -227,7 +227,8 @@ export class EditProfileComponent extends Component<IEditProfileComponentProps,I
|
||||
fullName: fullNameInput,
|
||||
tagLine: tagLineInput,
|
||||
avatar: avatar,
|
||||
banner: banner
|
||||
banner: banner,
|
||||
creationDate: this.props.info!.creationDate
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import InfiniteScroll from 'react-infinite-scroller'
|
||||
|
||||
// - Import app components
|
||||
import UserBoxList from 'components/userBoxList'
|
||||
import LoadMoreProgressComponent from 'layouts/loadMoreProgress'
|
||||
|
||||
// - Import API
|
||||
|
||||
@@ -20,10 +21,6 @@ import { IFindPeopleComponentState } from './IFindPeopleComponentState'
|
||||
*/
|
||||
export class FindPeopleComponent extends Component<IFindPeopleComponentProps, IFindPeopleComponentState> {
|
||||
|
||||
static propTypes = {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Component constructor
|
||||
* @param {object} props is an object properties of component
|
||||
@@ -36,49 +33,32 @@ export class FindPeopleComponent extends Component<IFindPeopleComponentProps, IF
|
||||
|
||||
}
|
||||
|
||||
// Binding functions to `this`
|
||||
|
||||
}
|
||||
|
||||
loadItems (page: number) {
|
||||
console.log('------------------------')
|
||||
console.log(page)
|
||||
console.log('------------------------')
|
||||
/**
|
||||
* Scroll loader
|
||||
*/
|
||||
scrollLoad = (page: number) => {
|
||||
const {loadPeople} = this.props
|
||||
loadPeople!(page, 10)
|
||||
}
|
||||
|
||||
componentWillMount () {
|
||||
this.props.loadPeople!()
|
||||
}
|
||||
/**
|
||||
* Reneder component DOM
|
||||
* @return {react element} return the DOM which rendered by component
|
||||
*/
|
||||
render () {
|
||||
|
||||
const styles = {
|
||||
paper: {
|
||||
height: 254,
|
||||
width: 243,
|
||||
margin: 10,
|
||||
textAlign: 'center',
|
||||
maxWidth: '257px'
|
||||
},
|
||||
followButton: {
|
||||
position: 'absolute',
|
||||
bottom: '8px',
|
||||
left: 0,
|
||||
right: 0
|
||||
}
|
||||
}
|
||||
const loader = <div className='loader'>Loading ...</div>
|
||||
const {hasMorePeople} = this.props
|
||||
|
||||
return (
|
||||
<div>
|
||||
<InfiniteScroll
|
||||
pageStart={0}
|
||||
loadMore={this.loadItems.bind(this)}
|
||||
hasMore={false}
|
||||
loader={loader}>
|
||||
loadMore={this.scrollLoad}
|
||||
hasMore={hasMorePeople}
|
||||
useWindow={true}
|
||||
loader={ <LoadMoreProgressComponent />}
|
||||
>
|
||||
|
||||
<div className='tracks'>
|
||||
|
||||
@@ -106,7 +86,7 @@ export class FindPeopleComponent extends Component<IFindPeopleComponentProps, IF
|
||||
*/
|
||||
const mapDispatchToProps = (dispatch: any, ownProps: IFindPeopleComponentProps) => {
|
||||
return {
|
||||
loadPeople: () => dispatch(userActions.dbGetPeopleInfo())
|
||||
loadPeople: (page: number, limit: number) => dispatch(userActions.dbGetPeopleInfo(page, limit))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,8 +97,10 @@ const mapDispatchToProps = (dispatch: any, ownProps: IFindPeopleComponentProps)
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IFindPeopleComponentProps) => {
|
||||
const {people, info} = state.user
|
||||
return {
|
||||
peopleInfo: state.user.info
|
||||
peopleInfo: info,
|
||||
hasMorePeople: people.hasMoreData
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ export interface IFindPeopleComponentProps {
|
||||
*
|
||||
* @memberof IFindPeopleComponentProps
|
||||
*/
|
||||
loadPeople?: () => any
|
||||
loadPeople?: (page: number, limit: number) => any
|
||||
|
||||
/**
|
||||
* Users' profile
|
||||
@@ -17,4 +17,9 @@ export interface IFindPeopleComponentProps {
|
||||
*/
|
||||
peopleInfo?: {[userId: string]: Profile}
|
||||
|
||||
/**
|
||||
* If there are more people {true} or not {false}
|
||||
*/
|
||||
hasMorePeople: boolean
|
||||
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import UserBoxList from 'components/userBoxList'
|
||||
|
||||
import { IFollowersComponentProps } from './IFollowersComponentProps'
|
||||
import { IFollowersComponentState } from './IFollowersComponentState'
|
||||
import { Circle } from 'core/domain/circles';
|
||||
|
||||
// - Import API
|
||||
|
||||
@@ -79,10 +80,11 @@ const mapDispatchToProps = (dispatch: any,ownProps: IFollowersComponentProps) =>
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any,ownProps: IFollowersComponentProps) => {
|
||||
const {circle, authorize, server} = state
|
||||
const { uid } = state.authorize
|
||||
const circles = state.circle ? state.circle.userCircles[uid] : {}
|
||||
const circles: { [circleId: string]: Circle } = circle ? (circle.circleList || {}) : {}
|
||||
return{
|
||||
followers: circles ? (circles['-Followers'] ? circles['-Followers'].users || {} : {}) : {}
|
||||
followers: circles ? circles.userTieds : {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { UserFollower } from 'core/domain/circles'
|
||||
import { UserTie } from 'core/domain/circles'
|
||||
|
||||
export interface IFollowersComponentProps {
|
||||
|
||||
/**
|
||||
* User followers info
|
||||
*
|
||||
* @type {{[userId: string]: UserFollower}}
|
||||
* @type {{[userId: string]: UserTie}}
|
||||
* @memberof IFindPeopleComponentProps
|
||||
*/
|
||||
followers?: {[userId: string]: UserFollower}
|
||||
followers?: {[userId: string]: UserTie}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import UserBoxList from 'components/userBoxList'
|
||||
import CircleAPI from 'api/CircleAPI'
|
||||
import { IFollowingComponentProps } from './IFollowingComponentProps'
|
||||
import { IFollowingComponentState } from './IFollowingComponentState'
|
||||
import { Circle } from 'core/domain/circles';
|
||||
|
||||
// - Import actions
|
||||
|
||||
@@ -80,9 +81,10 @@ const mapDispatchToProps = (dispatch: any,ownProp: IFollowingComponentProps) =>
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any,ownProps: IFollowingComponentProps) => {
|
||||
const {circle, authorize, server} = state
|
||||
const { uid } = state.authorize
|
||||
const circles = state.circle ? state.circle.userCircles[uid] : {}
|
||||
const followingUsers = CircleAPI.getFollowingUsers(circles)
|
||||
const circles: { [circleId: string]: Circle } = circle ? (circle.circleList || {}) : {}
|
||||
const followingUsers = circle ? circle.userTies : {}
|
||||
return {
|
||||
uid,
|
||||
circles,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UserFollower } from 'core/domain/circles'
|
||||
import { UserTie } from 'core/domain/circles'
|
||||
|
||||
export interface IFollowingComponentProps {
|
||||
|
||||
followingUsers?: {[userId: string]: UserFollower}
|
||||
followingUsers?: {[userId: string]: UserTie}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,6 @@ export class HomeComponent extends Component<IHomeComponentProps, IHomeComponent
|
||||
}
|
||||
|
||||
componentWillMount () {
|
||||
|
||||
const {global, clearData, loadData, authed, defaultDataEnable, isVerifide, goTo } = this.props
|
||||
if (!authed) {
|
||||
goTo!('/login')
|
||||
@@ -131,7 +130,7 @@ export class HomeComponent extends Component<IHomeComponentProps, IHomeComponent
|
||||
* @memberof Home
|
||||
*/
|
||||
render () {
|
||||
const {loaded, authed, mergedPosts} = this.props
|
||||
const {loaded, authed, loadDataStream, mergedPosts, hasMorePosts} = this.props
|
||||
return (
|
||||
<div id='home'>
|
||||
<HomeHeader sidebar={this.state.sidebarOpen} sidebarStatus={this.state.sidebarStatus} />
|
||||
@@ -153,7 +152,7 @@ export class HomeComponent extends Component<IHomeComponentProps, IHomeComponent
|
||||
</SidebarContent>
|
||||
|
||||
<SidebarMain>
|
||||
<HomeRouter enabled={loaded!} data={{mergedPosts}} />
|
||||
<HomeRouter enabled={loaded!} data={{ mergedPosts, loadDataStream, hasMorePosts}} />
|
||||
</SidebarMain>
|
||||
</Sidebar>
|
||||
|
||||
@@ -167,12 +166,15 @@ export class HomeComponent extends Component<IHomeComponentProps, IHomeComponent
|
||||
const mapDispatchToProps = (dispatch: any, ownProps: IHomeComponentProps) => {
|
||||
|
||||
return {
|
||||
loadDataStream:
|
||||
(page: number, limit: number) => dispatch(postActions.dbGetPosts(page,limit)),
|
||||
loadData: () => {
|
||||
dispatch(imageGalleryActions.dbGetImageGallery())
|
||||
dispatch(postActions.dbGetPosts())
|
||||
dispatch(imageGalleryActions.dbGetImageGallery())
|
||||
dispatch(userActions.dbGetUserInfo())
|
||||
dispatch(notifyActions.dbGetNotifications())
|
||||
dispatch(circleActions.dbGetCircles())
|
||||
dispatch(circleActions.dbGetUserTies())
|
||||
|
||||
},
|
||||
clearData: () => {
|
||||
@@ -205,9 +207,10 @@ const mapStateToProps = (state: any, ownProps: IHomeComponentProps) => {
|
||||
const { authorize, global, user, post, imageGallery, notify, circle } = state
|
||||
const { uid } = authorize
|
||||
let mergedPosts = {}
|
||||
const circles = circle ? (circle.userCircles[uid] || {}) : {}
|
||||
const followingUsers = CircleAPI.getFollowingUsers(circles)
|
||||
const circles = circle ? (circle.circleList || {}) : {}
|
||||
const followingUsers = circle ? circle.userTies : {}
|
||||
const posts = post.userPosts ? post.userPosts[authorize.uid] : {}
|
||||
const hasMorePosts = post.stream.hasMoreData
|
||||
Object.keys(followingUsers).forEach((userId) => {
|
||||
let newPosts = post.userPosts ? post.userPosts[userId] : {}
|
||||
_.merge(mergedPosts,newPosts)
|
||||
@@ -219,9 +222,10 @@ const mapStateToProps = (state: any, ownProps: IHomeComponentProps) => {
|
||||
mainStyle: global.sidebarMainStyle,
|
||||
mergedPosts,
|
||||
global,
|
||||
hasMorePosts,
|
||||
loaded: user.loaded && post.loaded && imageGallery.loaded && notify.loaded && circle.loaded
|
||||
}
|
||||
}
|
||||
|
||||
// - Connect component to redux store
|
||||
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(HomeComponent as any))
|
||||
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(HomeComponent as any) as any)
|
||||
|
||||
@@ -24,7 +24,7 @@ export interface IHomeComponentProps {
|
||||
* @type {string}
|
||||
* @memberof IHomeComponentProps
|
||||
*/
|
||||
uid: string
|
||||
uid?: string
|
||||
|
||||
/**
|
||||
* Merged all users posts to show in stream
|
||||
@@ -34,6 +34,11 @@ export interface IHomeComponentProps {
|
||||
*/
|
||||
mergedPosts?: {[postId: string]: Post}
|
||||
|
||||
/**
|
||||
* Load the data for stream
|
||||
*/
|
||||
loadDataStream: (lastPostId: string, page: number, limit: number) => any
|
||||
|
||||
/**
|
||||
* Global state
|
||||
*
|
||||
@@ -80,6 +85,11 @@ export interface IHomeComponentProps {
|
||||
*/
|
||||
goTo?: (url: string) => any
|
||||
|
||||
/**
|
||||
* If there is more post {true} or not {false}
|
||||
*/
|
||||
hasMorePosts?: boolean
|
||||
|
||||
/**
|
||||
* If all requierment data loaded {true} or not {false}
|
||||
*
|
||||
|
||||
@@ -29,7 +29,6 @@ export class HomeHeaderComponent extends Component<IHomeHeaderComponentProps,IHo
|
||||
|
||||
styles = {
|
||||
toolbarStyle: {
|
||||
backgroundColor: '',
|
||||
transition: 'all 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms',
|
||||
boxSizing: 'border-box',
|
||||
fontFamily: 'Roboto, sans-serif',
|
||||
@@ -187,7 +186,7 @@ export class HomeHeaderComponent extends Component<IHomeHeaderComponentProps,IHo
|
||||
|
||||
return (
|
||||
|
||||
<Toolbar style={this.styles.toolbarStyle as any} className='g__greenBox'>
|
||||
<Toolbar style={this.styles.toolbarStyle as any}>
|
||||
<EventListener
|
||||
target='window'
|
||||
onResize={this.handleResize}
|
||||
|
||||
@@ -191,4 +191,4 @@ const mapStateToProps = (state: any) => {
|
||||
|
||||
}
|
||||
// - Connect commponent to redux store
|
||||
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(MasterComponent as any))
|
||||
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(MasterComponent as any) as any)
|
||||
|
||||
@@ -17,7 +17,7 @@ export interface IPostComponentProps {
|
||||
* @type {string}
|
||||
* @memberof IPostComponentProps
|
||||
*/
|
||||
avatar: string
|
||||
avatar?: string
|
||||
|
||||
/**
|
||||
* User full name
|
||||
@@ -105,7 +105,7 @@ export interface IPostComponentProps {
|
||||
*
|
||||
* @memberof IPostComponentProps
|
||||
*/
|
||||
getPostComments: (ownerUserId: string, postId: string) => any
|
||||
getPostComments?: (ownerUserId: string, postId: string) => any
|
||||
|
||||
/**
|
||||
* Commnets
|
||||
|
||||
@@ -87,7 +87,7 @@ export class PostComponent extends Component<IPostComponentProps,IPostComponentS
|
||||
/**
|
||||
* Post text
|
||||
*/
|
||||
text: post.body!,
|
||||
text: post.body ? post.body : '',
|
||||
/**
|
||||
* It's true if whole the text post is visible
|
||||
*/
|
||||
@@ -409,7 +409,7 @@ const mapDispatchToProps = (dispatch: any, ownProps: IPostComponentProps) => {
|
||||
const mapStateToProps = (state: any, ownProps: IPostComponentProps) => {
|
||||
const {post, vote, authorize, comment} = state
|
||||
const {uid} = authorize
|
||||
let currentUserVote = post.votes ? post.votes[uid] : false
|
||||
let currentUserVote = ownProps.post.votes ? ownProps.post.votes[uid] : false
|
||||
const postModel = post.userPosts[ownProps.post.ownerUserId!][ownProps.post.id!]
|
||||
const postOwner = (post.userPosts[uid] ? Object.keys(post.userPosts[uid]).filter((key) => { return ownProps.post.id === key }).length : 0)
|
||||
const commentList: { [commentId: string]: Comment } = comment.postComments[ownProps.post.id!]
|
||||
|
||||
@@ -50,12 +50,12 @@ export interface IPostWriteComponentProps {
|
||||
/**
|
||||
* The post owner name
|
||||
*/
|
||||
ownerDisplayName: string
|
||||
ownerDisplayName?: string
|
||||
|
||||
/**
|
||||
* Post model
|
||||
*/
|
||||
postModel: Post
|
||||
postModel?: Post
|
||||
|
||||
/**
|
||||
* Save a post
|
||||
|
||||
@@ -49,15 +49,15 @@ export class PostWriteComponent extends Component<IPostWriteComponentProps,IPost
|
||||
/**
|
||||
* Post text
|
||||
*/
|
||||
postText: this.props.edit ? this.props.text! : '',
|
||||
postText: this.props.edit && postModel ? (postModel.body ? postModel.body! : '' ) : '',
|
||||
/**
|
||||
* The URL image of the post
|
||||
*/
|
||||
image: this.props.edit ? this.props.image : '',
|
||||
image: this.props.edit && postModel ? (postModel.image ? postModel.image! : '' ) : '',
|
||||
/**
|
||||
* The path identifier of image on the server
|
||||
*/
|
||||
imageFullPath: this.props.edit ? (postModel.imageFullPath ? postModel.imageFullPath! : '' ) : '',
|
||||
imageFullPath: this.props.edit && postModel ? (postModel.imageFullPath ? postModel.imageFullPath! : '' ) : '',
|
||||
/**
|
||||
* If it's true gallery will be open
|
||||
*/
|
||||
@@ -69,11 +69,11 @@ export class PostWriteComponent extends Component<IPostWriteComponentProps,IPost
|
||||
/**
|
||||
* If it's true comment will be disabled on post
|
||||
*/
|
||||
disableComments: this.props.edit ? postModel.disableComments! : false,
|
||||
disableComments: this.props.edit && postModel ? postModel.disableComments! : false,
|
||||
/**
|
||||
* If it's true share will be disabled on post
|
||||
*/
|
||||
disableSharing: this.props.edit ? postModel.disableSharing! : false
|
||||
disableSharing: this.props.edit && postModel ? postModel.disableSharing! : false
|
||||
|
||||
}
|
||||
|
||||
@@ -190,14 +190,14 @@ export class PostWriteComponent extends Component<IPostWriteComponentProps,IPost
|
||||
}, onRequestClose)
|
||||
}
|
||||
} else { // In edit status we pass post to update functions
|
||||
postModel.body = postText
|
||||
postModel.tags = tags
|
||||
postModel.image = image
|
||||
postModel.imageFullPath = imageFullPath
|
||||
postModel.disableComments = disableComments
|
||||
postModel.disableSharing = disableSharing
|
||||
postModel!.body = postText
|
||||
postModel!.tags = tags
|
||||
postModel!.image = image
|
||||
postModel!.imageFullPath = imageFullPath
|
||||
postModel!.disableComments = disableComments
|
||||
postModel!.disableSharing = disableSharing
|
||||
|
||||
update!(postModel, onRequestClose)
|
||||
update!(postModel!, onRequestClose)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,30 +255,34 @@ export class PostWriteComponent extends Component<IPostWriteComponentProps,IPost
|
||||
if (!nextProps.open) {
|
||||
const {postModel} = this.props
|
||||
this.setState({
|
||||
/**
|
||||
* Post text
|
||||
*/
|
||||
postText: this.props.edit ? this.props.text! : '',
|
||||
/**
|
||||
* The image of the post
|
||||
*/
|
||||
image: this.props.edit ? this.props.image! : '',
|
||||
/**
|
||||
* If it's true gallery will be open
|
||||
*/
|
||||
/**
|
||||
* Post text
|
||||
*/
|
||||
postText: this.props.edit && postModel ? (postModel.body ? postModel.body! : '' ) : '',
|
||||
/**
|
||||
* The URL image of the post
|
||||
*/
|
||||
image: this.props.edit && postModel ? (postModel.image ? postModel.image! : '' ) : '',
|
||||
/**
|
||||
* The path identifier of image on the server
|
||||
*/
|
||||
imageFullPath: this.props.edit && postModel ? (postModel.imageFullPath ? postModel.imageFullPath! : '' ) : '',
|
||||
/**
|
||||
* If it's true gallery will be open
|
||||
*/
|
||||
galleryOpen: false,
|
||||
/**
|
||||
* If it's true post button will be disabled
|
||||
*/
|
||||
/**
|
||||
* If it's true post button will be disabled
|
||||
*/
|
||||
disabledPost: true,
|
||||
/**
|
||||
* If it's true comment will be disabled on post
|
||||
*/
|
||||
disableComments: this.props.edit ? postModel.disableComments! : false,
|
||||
/**
|
||||
* If it's true share will be disabled on post
|
||||
*/
|
||||
disableSharing: this.props.edit ? postModel.disableSharing! : false
|
||||
/**
|
||||
* If it's true comment will be disabled on post
|
||||
*/
|
||||
disableComments: this.props.edit && postModel ? postModel.disableComments! : false,
|
||||
/**
|
||||
* If it's true share will be disabled on post
|
||||
*/
|
||||
disableSharing: this.props.edit && postModel ? postModel.disableSharing! : false
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@@ -79,4 +79,9 @@ export interface IProfileComponentProps {
|
||||
* @memberof IProfileComponentProps
|
||||
*/
|
||||
loadUserInfo: () => any
|
||||
|
||||
/**
|
||||
* If there is more posts to show in profile
|
||||
*/
|
||||
hasMorePosts: boolean
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ export class ProfileComponent extends Component<IProfileComponentProps,IProfileC
|
||||
border: '2px solid rgb(255, 255, 255)'
|
||||
}
|
||||
}
|
||||
const {loadPosts, hasMorePosts} = this.props
|
||||
|
||||
return (
|
||||
<div style={styles.profile}>
|
||||
@@ -91,7 +92,11 @@ export class ProfileComponent extends Component<IProfileComponentProps,IProfileC
|
||||
</div>
|
||||
<div style={{ height: '24px' }}></div>
|
||||
|
||||
<StreamComponent posts={this.props.posts} displayWriting={false} />
|
||||
<StreamComponent
|
||||
posts={this.props.posts}
|
||||
loadStream={loadPosts}
|
||||
hasMorePosts={hasMorePosts}
|
||||
displayWriting={false} />
|
||||
</div>)
|
||||
: (<div className='profile__title'>
|
||||
Nothing shared
|
||||
@@ -127,6 +132,7 @@ const mapDispatchToProps = (dispatch: any, ownProps: IProfileComponentProps) =>
|
||||
const mapStateToProps = (state: any, ownProps: IProfileComponentProps) => {
|
||||
const { userId } = ownProps.match.params
|
||||
const {uid} = state.authorize
|
||||
const hasMorePosts = state.post.profile.hasMoreData
|
||||
return {
|
||||
avatar: state.user.info && state.user.info[userId] ? state.user.info[userId].avatar || '' : '',
|
||||
name: state.user.info && state.user.info[userId] ? state.user.info[userId].fullName || '' : '',
|
||||
@@ -134,7 +140,8 @@ const mapStateToProps = (state: any, ownProps: IProfileComponentProps) => {
|
||||
tagLine: state.user.info && state.user.info[userId] ? state.user.info[userId].tagLine || '' : '',
|
||||
posts: state.post.userPosts ? state.post.userPosts[userId] : {},
|
||||
isAuthedUser: userId === uid,
|
||||
userId
|
||||
userId,
|
||||
hasMorePosts
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
92
src/components/profile/dialogTitle/DialogTitleComponent.tsx
Normal file
92
src/components/profile/dialogTitle/DialogTitleComponent.tsx
Normal file
@@ -0,0 +1,92 @@
|
||||
// - Import react components
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { grey400 } from 'material-ui/styles/colors'
|
||||
import SvgClose from 'material-ui/svg-icons/navigation/close'
|
||||
import FlatButton from 'material-ui/FlatButton'
|
||||
import Divider from 'material-ui/Divider'
|
||||
import { IDialogTitleComponentProps } from './IDialogTitleComponentProps'
|
||||
import { IDialogTitleComponentState } from './IDialogTitleComponentState'
|
||||
|
||||
/**
|
||||
* Create component class
|
||||
*/
|
||||
export default class DialogTitleComponent extends Component<IDialogTitleComponentProps,IDialogTitleComponentState> {
|
||||
|
||||
static propTypes = {
|
||||
/**
|
||||
* The label of right button
|
||||
*/
|
||||
buttonLabel: PropTypes.string,
|
||||
/**
|
||||
* If it's true button will be disabled
|
||||
*/
|
||||
disabledButton: PropTypes.bool,
|
||||
/**
|
||||
* Call the funtion the time is clicked on right button
|
||||
*/
|
||||
onClickButton: PropTypes.func,
|
||||
/**
|
||||
* The function will be called the time is clicked on close
|
||||
*/
|
||||
onRequestClose: PropTypes.func.isRequired,
|
||||
/**
|
||||
* The title of dialog box
|
||||
*/
|
||||
title: PropTypes.string
|
||||
}
|
||||
|
||||
styles = {
|
||||
contain: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between'
|
||||
},
|
||||
title: {
|
||||
color: 'rgba(0,0,0,0.87)',
|
||||
flex: '1 1',
|
||||
font: '500 20px Roboto,RobotoDraft,Helvetica,Arial,sans-serif'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Component constructor
|
||||
* @param {object} props is an object properties of component
|
||||
*/
|
||||
constructor (props: IDialogTitleComponentProps) {
|
||||
super(props)
|
||||
|
||||
// Defaul state
|
||||
this.state = {
|
||||
}
|
||||
|
||||
// Binding functions to `this`
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reneder component DOM
|
||||
* @return {react element} return the DOM which rendered by component
|
||||
*/
|
||||
render () {
|
||||
|
||||
const { buttonLabel, disabledButton, onClickButton, onRequestClose, title } = this.props
|
||||
|
||||
return (
|
||||
<div className='g__dialog-title'>
|
||||
<div style={this.styles.contain as any}>
|
||||
<div style={{ paddingRight: '10px' }}>
|
||||
<SvgClose onClick={onRequestClose} hoverColor={grey400} style={{ cursor: 'pointer' }} />
|
||||
</div>
|
||||
<div style={this.styles.title}>
|
||||
{title || ''}
|
||||
</div>
|
||||
{ buttonLabel ? (<div style={{ marginTop: '-9px' }}>
|
||||
<FlatButton label={buttonLabel || ''} primary={true} disabled={disabledButton ? disabledButton : false} onClick={onClickButton || (x => x)} />
|
||||
</div>) : ''}
|
||||
</div>
|
||||
<Divider />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
export interface IDialogTitleComponentProps {
|
||||
|
||||
/**
|
||||
* Lable of the button
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof IDialogTitleComponentProps
|
||||
*/
|
||||
buttonLabel?: string
|
||||
|
||||
/**
|
||||
* Dialog tile
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof IDialogTitleComponentProps
|
||||
*/
|
||||
title: string
|
||||
|
||||
/**
|
||||
* Button is disabled {true} or not {false}
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof IDialogTitleComponentProps
|
||||
*/
|
||||
disabledButton?: boolean
|
||||
|
||||
/**
|
||||
* On click event
|
||||
*
|
||||
* @memberof IDialogTitleComponentProps
|
||||
*/
|
||||
onClickButton?: (event: any) => void
|
||||
|
||||
/**
|
||||
* On request close event
|
||||
*
|
||||
* @memberof IDialogTitleComponentProps
|
||||
*/
|
||||
onRequestClose: (event: any) => void
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export interface IDialogTitleComponentState {
|
||||
|
||||
}
|
||||
2
src/components/profile/dialogTitle/index.ts
Normal file
2
src/components/profile/dialogTitle/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
import DialogTitleComponent from './DialogTitleComponent'
|
||||
export default DialogTitleComponent
|
||||
@@ -66,12 +66,26 @@ export interface IStreamComponentProps {
|
||||
*/
|
||||
avatar?: string
|
||||
|
||||
/**
|
||||
* Load the data for stream
|
||||
*/
|
||||
loadStream: (page: number, limit: number) => any
|
||||
|
||||
/**
|
||||
* If there is more post {true} or not {false}
|
||||
*/
|
||||
hasMorePosts: boolean
|
||||
|
||||
/**
|
||||
* Posts for stream
|
||||
*
|
||||
* @type {{[postId: string]: Post}}
|
||||
* @memberof IStreamComponentProps
|
||||
*/
|
||||
posts?: {[postId: string]: Post}
|
||||
posts: {[postId: string]: Post}
|
||||
|
||||
/**
|
||||
* Router match property
|
||||
*/
|
||||
match: any
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Post } from 'core/domain/posts'
|
||||
|
||||
export interface IStreamComponentState {
|
||||
|
||||
@@ -34,7 +35,15 @@ export interface IStreamComponentState {
|
||||
divided: boolean
|
||||
|
||||
/**
|
||||
* The tile of top bar
|
||||
* If there is more post to show
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof IStreamComponentState
|
||||
*/
|
||||
hasMorePosts: boolean
|
||||
|
||||
/**
|
||||
* The title of top bar
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof IStreamComponentState
|
||||
|
||||
@@ -5,15 +5,18 @@ import { connect } from 'react-redux'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Card, CardActions, CardHeader, CardMedia, CardTitle, CardText } from 'material-ui/Card'
|
||||
import FlatButton from 'material-ui/FlatButton'
|
||||
import { grey400, grey800, darkBlack, lightBlack } from 'material-ui/styles/colors'
|
||||
import { grey400, grey800, darkBlack, lightBlack,tealA400 } from 'material-ui/styles/colors'
|
||||
import CircularProgress from 'material-ui/CircularProgress'
|
||||
import SvgCamera from 'material-ui/svg-icons/image/photo-camera'
|
||||
import Paper from 'material-ui/Paper'
|
||||
import { List, ListItem } from 'material-ui/List'
|
||||
import InfiniteScroll from 'react-infinite-scroller'
|
||||
|
||||
// - Import app components
|
||||
import PostComponent from 'components/post'
|
||||
import PostWriteComponent from 'components/postWrite'
|
||||
import UserAvatarComponent from 'components/userAvatar'
|
||||
import LoadMoreProgressComponent from 'layouts/loadMoreProgress'
|
||||
|
||||
// - Import API
|
||||
import * as PostAPI from 'api/PostAPI'
|
||||
@@ -23,6 +26,7 @@ import * as globalActions from 'actions/globalActions'
|
||||
|
||||
import { IStreamComponentProps } from './IStreamComponentProps'
|
||||
import { IStreamComponentState } from './IStreamComponentState'
|
||||
import { Post } from 'core/domain/posts'
|
||||
|
||||
// - Create StreamComponent component class
|
||||
export class StreamComponent extends Component<IStreamComponentProps,IStreamComponentState> {
|
||||
@@ -82,7 +86,12 @@ export class StreamComponent extends Component<IStreamComponentProps,IStreamComp
|
||||
/**
|
||||
* The title of home header
|
||||
*/
|
||||
homeTitle: props.homeTitle!
|
||||
homeTitle: props.homeTitle!,
|
||||
|
||||
/**
|
||||
* If there is more post to show {true} or not {false}
|
||||
*/
|
||||
hasMorePosts: true
|
||||
}
|
||||
|
||||
// Binding functions to `this`
|
||||
@@ -115,13 +124,13 @@ export class StreamComponent extends Component<IStreamComponentProps,IStreamComp
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a list of posts
|
||||
* @return {DOM} posts
|
||||
*/
|
||||
/**
|
||||
* Create a list of posts
|
||||
* @return {DOM} posts
|
||||
*/
|
||||
postLoad = () => {
|
||||
|
||||
let { posts ,match }: any = this.props
|
||||
let { posts ,match } = this.props
|
||||
let {tag} = match.params
|
||||
if (posts === undefined || !(Object.keys(posts).length > 0)) {
|
||||
|
||||
@@ -139,7 +148,7 @@ export class StreamComponent extends Component<IStreamComponentProps,IStreamComp
|
||||
Object.keys(posts).forEach((postId) => {
|
||||
if (tag) {
|
||||
let regex = new RegExp('#' + tag,'g')
|
||||
let postMatch = posts[postId].body.match(regex)
|
||||
let postMatch = posts[postId].body!.match(regex)
|
||||
if (postMatch !== null) {
|
||||
parsedPosts.push({ ...posts[postId]})
|
||||
}
|
||||
@@ -177,6 +186,14 @@ export class StreamComponent extends Component<IStreamComponentProps,IStreamComp
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll loader
|
||||
*/
|
||||
scrollLoad = (page: number) => {
|
||||
const {loadStream} = this.props
|
||||
loadStream(page, 10)
|
||||
}
|
||||
|
||||
componentWillMount () {
|
||||
const {setHomeTitle} = this.props
|
||||
setHomeTitle!()
|
||||
@@ -188,14 +205,18 @@ export class StreamComponent extends Component<IStreamComponentProps,IStreamComp
|
||||
*/
|
||||
render () {
|
||||
|
||||
let postList: any = this.postLoad()
|
||||
|
||||
const {tag, displayWriting } = this.props
|
||||
const {tag, displayWriting, hasMorePosts } = this.props
|
||||
const postList = this.postLoad() as {evenPostList: Post[], oddPostList: Post[], divided: boolean} | any
|
||||
|
||||
return (
|
||||
<div >
|
||||
<InfiniteScroll
|
||||
pageStart={0}
|
||||
loadMore={this.scrollLoad}
|
||||
hasMore={hasMorePosts}
|
||||
useWindow={true}
|
||||
loader={ <LoadMoreProgressComponent />}
|
||||
>
|
||||
<div className='grid grid__gutters grid__1of2 grid__space-around animate-top'>
|
||||
|
||||
<div className='grid-cell animate-top' style= {{maxWidth: '530px', minWidth: '280px'}}>
|
||||
{displayWriting && !tag
|
||||
? (<PostWriteComponent open={this.state.openPostWrite} onRequestClose={this.handleClosePostWrite} edit={false} >
|
||||
@@ -225,9 +246,10 @@ export class StreamComponent extends Component<IStreamComponentProps,IStreamComp
|
||||
</div>
|
||||
</div>)
|
||||
: ''}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</InfiniteScroll>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -254,6 +276,7 @@ const mapDispatchToProps = (dispatch: any, ownProps: IStreamComponentProps) => {
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IStreamComponentProps) => {
|
||||
const {post} = state
|
||||
return {
|
||||
avatar: state.user.info && state.user.info[state.authorize.uid] ? state.user.info[state.authorize.uid].avatar : '',
|
||||
fullName: state.user.info && state.user.info[state.authorize.uid] ? state.user.info[state.authorize.uid].fullName : ''
|
||||
@@ -261,4 +284,4 @@ const mapStateToProps = (state: any, ownProps: IStreamComponentProps) => {
|
||||
}
|
||||
|
||||
// - Connect component to redux store
|
||||
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(StreamComponent as any))
|
||||
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(StreamComponent as any) as any)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { User } from 'core/domain/users'
|
||||
import { Circle } from 'core/domain/circles/circle'
|
||||
import { UserFollower } from 'core/domain/circles'
|
||||
import { UserTie } from 'core/domain/circles'
|
||||
|
||||
export interface IUserBoxComponentProps {
|
||||
|
||||
@@ -18,7 +18,7 @@ export interface IUserBoxComponentProps {
|
||||
* @type {User}
|
||||
* @memberof IUserBoxComponentProps
|
||||
*/
|
||||
user: UserFollower
|
||||
user: UserTie
|
||||
|
||||
/**
|
||||
* Circles
|
||||
@@ -36,6 +36,11 @@ export interface IUserBoxComponentProps {
|
||||
*/
|
||||
userBelongCircles?: string[]
|
||||
|
||||
/**
|
||||
* Whether current user followed this user
|
||||
*/
|
||||
isFollowed: boolean
|
||||
|
||||
/**
|
||||
* The number of circles
|
||||
*
|
||||
@@ -80,7 +85,7 @@ export interface IUserBoxComponentProps {
|
||||
*
|
||||
* @memberof IUserBoxComponentProps
|
||||
*/
|
||||
addFollowingUser?: (cid: string,user: UserFollower) => any
|
||||
addFollowingUser?: (cid: string,user: UserTie) => any
|
||||
|
||||
/**
|
||||
* Delete
|
||||
|
||||
@@ -2,12 +2,20 @@
|
||||
export interface IUserBoxComponentState {
|
||||
|
||||
/**
|
||||
* Add new circle button is disabled {true} or not {false}
|
||||
* Create new circle button is disabled {true} or not {false}
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof IUserBoxComponentState
|
||||
*/
|
||||
disabledAddCircle: boolean
|
||||
disabledCreateCircle: boolean
|
||||
|
||||
/**
|
||||
* The button of add user in a circle is disabled {true} or not {false}
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof IUserBoxComponentState
|
||||
*/
|
||||
disabledAddToCircle: boolean
|
||||
|
||||
/**
|
||||
* Circle name
|
||||
@@ -32,4 +40,15 @@ export interface IUserBoxComponentState {
|
||||
* @memberof IUserBoxComponentState
|
||||
*/
|
||||
open: boolean
|
||||
|
||||
/**
|
||||
* Whether current user changed the selected circles for referer user
|
||||
*
|
||||
*/
|
||||
disabledDoneCircles: boolean
|
||||
|
||||
/**
|
||||
* Keep selected circles for refere user
|
||||
*/
|
||||
selectedCircles: string[]
|
||||
}
|
||||
|
||||
@@ -11,12 +11,17 @@ import Menu from 'material-ui/Menu'
|
||||
import MenuItem from 'material-ui/MenuItem'
|
||||
import Checkbox from 'material-ui/Checkbox'
|
||||
import TextField from 'material-ui/TextField'
|
||||
import { Dialog } from 'material-ui'
|
||||
import SvgAdd from 'material-ui/svg-icons/content/add'
|
||||
import IconButton from 'material-ui/IconButton'
|
||||
import { grey400, grey800, darkBlack, lightBlack } from 'material-ui/styles/colors'
|
||||
|
||||
// - Import app components
|
||||
import UserAvatar from 'components/userAvatar'
|
||||
|
||||
// - Import API
|
||||
import CircleAPI from 'api/CircleAPI'
|
||||
import StringAPI from 'api/StringAPI'
|
||||
|
||||
// - Import actions
|
||||
import * as circleActions from 'actions/circleActions'
|
||||
@@ -24,21 +29,22 @@ import * as circleActions from 'actions/circleActions'
|
||||
import { IUserBoxComponentProps } from './IUserBoxComponentProps'
|
||||
import { IUserBoxComponentState } from './IUserBoxComponentState'
|
||||
import { User } from 'core/domain/users'
|
||||
import { UserFollower, Circle } from 'core/domain/circles'
|
||||
import { UserTie, Circle } from 'core/domain/circles'
|
||||
import { ServerRequestType } from 'constants/serverRequestType'
|
||||
|
||||
/**
|
||||
* Create component class
|
||||
*/
|
||||
export class UserBoxComponent extends Component<IUserBoxComponentProps,IUserBoxComponentState> {
|
||||
export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBoxComponentState> {
|
||||
|
||||
static propTypes = {
|
||||
/**
|
||||
* User identifier
|
||||
*/
|
||||
/**
|
||||
* User identifier
|
||||
*/
|
||||
userId: PropTypes.string,
|
||||
/**
|
||||
* User information
|
||||
*/
|
||||
/**
|
||||
* User information
|
||||
*/
|
||||
user: PropTypes.object
|
||||
|
||||
}
|
||||
@@ -53,207 +59,297 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps,IUserBoxC
|
||||
},
|
||||
followButton: {
|
||||
position: 'absolute',
|
||||
bottom: '8px',
|
||||
bottom: '30px',
|
||||
left: 0,
|
||||
right: 0
|
||||
},
|
||||
dialog: {
|
||||
width: '',
|
||||
maxWidth: '280px',
|
||||
borderRadius: '4px'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Component constructor
|
||||
* @param {object} props is an object properties of component
|
||||
*/
|
||||
/**
|
||||
* Component constructor
|
||||
* @param {object} props is an object properties of component
|
||||
*/
|
||||
constructor (props: IUserBoxComponentProps) {
|
||||
super(props)
|
||||
|
||||
// Defaul state
|
||||
const { userBelongCircles, circles } = this.props
|
||||
// Defaul state
|
||||
this.state = {
|
||||
/**
|
||||
* It will be true if user follow popover is open
|
||||
*/
|
||||
/**
|
||||
* It will be true if user follow popover is open
|
||||
*/
|
||||
open: false,
|
||||
/**
|
||||
* The value of circle input
|
||||
*/
|
||||
/**
|
||||
* The value of circle input
|
||||
*/
|
||||
circleName: '',
|
||||
/**
|
||||
* It will be true if the text field for adding group is empty
|
||||
*/
|
||||
disabledAddCircle: true
|
||||
/**
|
||||
* It will be true if the text field for adding group is empty
|
||||
*/
|
||||
disabledCreateCircle: true,
|
||||
/**
|
||||
* The button of add user in a circle is disabled {true} or not {false}
|
||||
*/
|
||||
disabledAddToCircle: true,
|
||||
/**
|
||||
* Keep selected circles for refere user
|
||||
*/
|
||||
selectedCircles: userBelongCircles ? userBelongCircles!.slice() : [],
|
||||
/**
|
||||
* Whether current user changed the selected circles for referer user
|
||||
*/
|
||||
disabledDoneCircles: true
|
||||
}
|
||||
|
||||
// Binding functions to `this`
|
||||
// Binding functions to `this`
|
||||
this.handleChangeName = this.handleChangeName.bind(this)
|
||||
this.handleCreateCricle = this.handleCreateCricle.bind(this)
|
||||
this.onCreateCircle = this.onCreateCircle.bind(this)
|
||||
this.handleFollowUser = this.handleFollowUser.bind(this)
|
||||
this.handleFollowUser = this.handleFollowUser.bind(this)
|
||||
|
||||
}
|
||||
|
||||
handleFollowUser = (checked: boolean,cid: string) => {
|
||||
const {userId,user} = this.props
|
||||
const {avatar,fullName} = user
|
||||
/**
|
||||
* Handle follow user
|
||||
*/
|
||||
handleFollowUser = (checked: boolean, cid: string) => {
|
||||
const { userId, user } = this.props
|
||||
const { avatar, fullName } = user
|
||||
if (checked) {
|
||||
this.props.addFollowingUser!(cid,{avatar,userId,fullName})
|
||||
this.props.addFollowingUser!(cid, { avatar, userId, fullName })
|
||||
} else {
|
||||
this.props.deleteFollowingUser!(cid,userId)
|
||||
this.props.deleteFollowingUser!(cid, userId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle create circle
|
||||
*
|
||||
*
|
||||
* @memberof UserBox
|
||||
*/
|
||||
handleCreateCricle = () => {
|
||||
const {circleName} = this.state
|
||||
if (circleName && circleName.trim() !== '' ) {
|
||||
this.props.createCircle!(this.state.circleName)
|
||||
this.setState({
|
||||
circleName: '',
|
||||
disabledAddCircle: true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle change group name input to the state
|
||||
*
|
||||
*
|
||||
* @memberof UserBox
|
||||
*/
|
||||
handleChangeName = (event: any) => {
|
||||
this.setState({
|
||||
circleName: event.target.value,
|
||||
disabledAddCircle: (event.target.value === undefined || event.target.value.trim() === '')
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle touch tab on follow popover
|
||||
*
|
||||
*
|
||||
* @memberof UserBox
|
||||
*/
|
||||
handleTouchTap = (event: any) => {
|
||||
// This prevents ghost click.
|
||||
event.preventDefault()
|
||||
|
||||
this.setState({
|
||||
open: true,
|
||||
anchorEl: event.currentTarget
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle close follow popover
|
||||
*
|
||||
*
|
||||
* @memberof UserBox
|
||||
*/
|
||||
handleRequestClose = () => {
|
||||
/**
|
||||
* Handle request close for add circle box
|
||||
*/
|
||||
onRequestCloseAddCircle = () => {
|
||||
this.setState({
|
||||
open: false
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle request open for add circle box
|
||||
*/
|
||||
onRequestOpenAddCircle = () => {
|
||||
this.setState({
|
||||
open: true
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new circle
|
||||
*/
|
||||
onCreateCircle = () => {
|
||||
const { circleName } = this.state
|
||||
if (circleName && circleName.trim() !== '') {
|
||||
this.props.createCircle!(this.state.circleName)
|
||||
this.setState({
|
||||
circleName: '',
|
||||
disabledCreateCircle: true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle change group name input to the state
|
||||
*/
|
||||
handleChangeName = (event: any) => {
|
||||
this.setState({
|
||||
circleName: event.target.value,
|
||||
disabledCreateCircle: (event.target.value === undefined || event.target.value.trim() === '')
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
handleSelectCircle = (event: object, isInputChecked: boolean, circleId: string) => {
|
||||
const { userBelongCircles, circles } = this.props
|
||||
let selectedCircles = this.state.selectedCircles
|
||||
if (isInputChecked) {
|
||||
selectedCircles = [
|
||||
...selectedCircles,
|
||||
circleId
|
||||
]
|
||||
|
||||
} else {
|
||||
const circleIndex = selectedCircles.indexOf(circleId)
|
||||
selectedCircles.splice(circleIndex, 1)
|
||||
}
|
||||
this.setState({
|
||||
selectedCircles: selectedCircles,
|
||||
disabledDoneCircles: !this.selectedCircleChange(selectedCircles)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle follow user
|
||||
*/
|
||||
onFollowUser = (event: any) => {
|
||||
// This prevents ghost click
|
||||
event.preventDefault()
|
||||
this.onRequestOpenAddCircle()
|
||||
}
|
||||
|
||||
/**
|
||||
* Add user to the circle/circles
|
||||
*/
|
||||
onAddToCircle = () => {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a circle list of user which belong to
|
||||
*/
|
||||
circleList = () => {
|
||||
let { circles, userId, userBelongCircles } = this.props
|
||||
|
||||
if (circles) {
|
||||
|
||||
return Object.keys(circles).map((key, index) => {
|
||||
if (key.trim() !== '-Followers') {
|
||||
let isBelong = userBelongCircles!.indexOf(key) > -1
|
||||
|
||||
return <Checkbox
|
||||
key={key}
|
||||
style={{ padding: '10px' }}
|
||||
label={circles![key].name}
|
||||
labelStyle={{
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
width: '100%'
|
||||
}}
|
||||
onCheck={(evt,checked) => this.handleFollowUser(checked,key)}
|
||||
checked={isBelong}
|
||||
/>
|
||||
}
|
||||
return Object.keys(circles).map((circleId, index) => {
|
||||
const {selectedCircles} = this.state
|
||||
let isBelong = selectedCircles!.indexOf(circleId) > -1
|
||||
// Create checkbox for selected/unselected circle
|
||||
return <Checkbox
|
||||
key={circleId}
|
||||
style={{ padding: '10px' }}
|
||||
label={circles![circleId].name}
|
||||
labelStyle={{
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
width: '100%'
|
||||
}}
|
||||
onCheck={(event: object, isInputChecked: boolean) => this.handleSelectCircle(event, isInputChecked, circleId)}
|
||||
checked={isBelong}
|
||||
/>
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reneder component DOM
|
||||
* @return {react element} return the DOM which rendered by component
|
||||
*/
|
||||
/**
|
||||
* Check if the the selected circles changed
|
||||
*/
|
||||
selectedCircleChange = (selectedCircles: string[]) => {
|
||||
let isChanged = false
|
||||
const { userBelongCircles, circles } = this.props
|
||||
|
||||
if (selectedCircles.length === userBelongCircles!.length) {
|
||||
for (let circleIndex: number = 0; circleIndex < selectedCircles.length; circleIndex++) {
|
||||
const selectedCircleId = selectedCircles[circleIndex]
|
||||
if (!(userBelongCircles!.indexOf(selectedCircleId) > -1)) {
|
||||
isChanged = true
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
isChanged = true
|
||||
}
|
||||
return isChanged
|
||||
}
|
||||
|
||||
/**
|
||||
* Reneder component DOM
|
||||
* @return {react element} return the DOM which rendered by component
|
||||
*/
|
||||
render () {
|
||||
const {disabledDoneCircles} = this.state
|
||||
const writeActions = [
|
||||
<FlatButton
|
||||
label='Cancel'
|
||||
primary={true}
|
||||
keyboardFocused={false}
|
||||
onTouchTap={this.onRequestCloseAddCircle}
|
||||
style={{ color: grey800 }}
|
||||
/>,
|
||||
<FlatButton
|
||||
label='Done'
|
||||
primary={true}
|
||||
keyboardFocused={false}
|
||||
disabled={disabledDoneCircles}
|
||||
onTouchTap={this.onCreateCircle}
|
||||
/>
|
||||
]
|
||||
|
||||
const { isFollowed } = this.props
|
||||
|
||||
return (
|
||||
<Paper style={this.styles.paper} zDepth={1} className='grid-cell'>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
height: '100%',
|
||||
position: 'relative',
|
||||
padding: '30px'
|
||||
<Paper style={this.styles.paper} zDepth={1} className='grid-cell'>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
height: '100%',
|
||||
position: 'relative',
|
||||
paddingTop: 20
|
||||
|
||||
}}>
|
||||
<div onClick={() => this.props.goTo!(`/${this.props.userId}`)} style={{cursor: 'pointer'}}>
|
||||
<UserAvatar
|
||||
fullName={this.props.fullName!}
|
||||
fileName={this.props.avatar!}
|
||||
size={90}
|
||||
/>
|
||||
</div>
|
||||
<div onClick={() => this.props.goTo!(`/${this.props.userId}`)} className='people__name' style={{cursor: 'pointer'}}>
|
||||
<div>
|
||||
{this.props.user.fullName}
|
||||
</div>
|
||||
</div>
|
||||
<div style={this.styles.followButton as any}>
|
||||
<FlatButton
|
||||
label={(this.props.belongCirclesCount && this.props.belongCirclesCount < 1) ? 'Follow'
|
||||
: (this.props.belongCirclesCount! > 1 ? `${this.props.belongCirclesCount} Circles` : ((this.props.firstBelongCircle) ? this.props.firstBelongCircle.name : 'Follow'))}
|
||||
primary={true}
|
||||
onTouchTap={this.handleTouchTap}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Popover
|
||||
open={this.state.open}
|
||||
anchorEl={this.state.anchorEl}
|
||||
anchorOrigin={{ horizontal: 'left', vertical: 'bottom' }}
|
||||
targetOrigin={{ horizontal: 'left', vertical: 'top' }}
|
||||
onRequestClose={this.handleRequestClose}
|
||||
animation={PopoverAnimationVertical}
|
||||
>
|
||||
<Menu >
|
||||
<div style={{
|
||||
position: 'relative',
|
||||
display: 'block',
|
||||
maxHeight: '220px'
|
||||
}}>
|
||||
<div style={{ overflowY: 'auto', height: '100%' }}>
|
||||
{this.circleList()}
|
||||
}}>
|
||||
<div onClick={() => this.props.goTo!(`/${this.props.userId}`)} style={{ cursor: 'pointer' }}>
|
||||
<UserAvatar
|
||||
fullName={this.props.fullName!}
|
||||
fileName={this.props.avatar!}
|
||||
size={90}
|
||||
/>
|
||||
</div>
|
||||
<div onClick={() => this.props.goTo!(`/${this.props.userId}`)} className='people__name' style={{ cursor: 'pointer' }}>
|
||||
<div>
|
||||
{this.props.user.fullName}
|
||||
</div>
|
||||
</div>
|
||||
<div style={this.styles.followButton as any}>
|
||||
<FlatButton
|
||||
label={!isFollowed ? 'Follow'
|
||||
: (this.props.belongCirclesCount! > 1 ? `${this.props.belongCirclesCount} Circles` : ((this.props.firstBelongCircle) ? this.props.firstBelongCircle.name : 'Follow'))}
|
||||
primary={true}
|
||||
onTouchTap={this.onFollowUser}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Dialog
|
||||
key={this.props.userId || 0}
|
||||
actions={writeActions}
|
||||
modal={false}
|
||||
open={this.state.open}
|
||||
contentStyle={this.styles.dialog}
|
||||
onRequestClose={this.onRequestCloseAddCircle}
|
||||
overlayStyle={{ background: 'rgba(0,0,0,0.12)' }}
|
||||
bodyStyle={{ padding: 0 }}
|
||||
autoDetectWindowHeight={false}
|
||||
actionsContainerStyle={{ borderTop: '1px solid rgb(224, 224, 224)' }}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ padding: '10px' }}>
|
||||
<TextField
|
||||
hintText='Group name'
|
||||
onChange={this.handleChangeName}
|
||||
value={this.state.circleName}
|
||||
/><br />
|
||||
<FlatButton label='ADD' primary={true} disabled={this.state.disabledAddCircle} onClick={this.handleCreateCricle} />
|
||||
</div>
|
||||
</Menu>
|
||||
</Popover>
|
||||
</Paper>
|
||||
>
|
||||
<div style={{
|
||||
position: 'relative',
|
||||
display: 'block',
|
||||
maxHeight: '220px'
|
||||
}}>
|
||||
<div style={{ overflowY: 'auto', height: '100%' }}>
|
||||
{this.circleList()}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ padding: '10px' }}>
|
||||
<TextField
|
||||
hintText='Group name'
|
||||
onChange={this.handleChangeName}
|
||||
value={this.state.circleName}
|
||||
/>
|
||||
<div className='user-box__add-circle'>
|
||||
<IconButton onClick={this.onCreateCircle} tooltip='Create circle' disabled={this.state.disabledCreateCircle}>
|
||||
<SvgAdd />
|
||||
</IconButton>
|
||||
</div>
|
||||
<br />
|
||||
</div>
|
||||
</Dialog>
|
||||
</Paper>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -267,8 +363,8 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps,IUserBoxC
|
||||
const mapDispatchToProps = (dispatch: Function, ownProps: IUserBoxComponentProps) => {
|
||||
return {
|
||||
createCircle: (name: string) => dispatch(circleActions.dbAddCircle(name)),
|
||||
addFollowingUser: (cid: string,user: UserFollower) => dispatch(circleActions.dbAddFollowingUser(cid,user)),
|
||||
deleteFollowingUser: (cid: string ,followingId: string) => dispatch(circleActions.dbDeleteFollowingUser(cid,followingId)),
|
||||
addFollowingUser: (circleIds: string[], user: UserTie) => dispatch(circleActions.dbUpdateUserInCircles(circleIds, user)),
|
||||
deleteFollowingUser: (cid: string, followingId: string) => dispatch(circleActions.dbDeleteFollowingUser(followingId)),
|
||||
goTo: (url: string) => dispatch(push(url))
|
||||
|
||||
}
|
||||
@@ -281,13 +377,17 @@ const mapDispatchToProps = (dispatch: Function, ownProps: IUserBoxComponentProps
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IUserBoxComponentProps) => {
|
||||
const { uid } = state.authorize
|
||||
const circles: {[circleId: string]: Circle} = state.circle ? (state.circle.userCircles[uid] || {}) : {}
|
||||
const userBelongCircles = CircleAPI.getUserBelongCircles(circles,ownProps.userId)
|
||||
|
||||
const { circle, authorize, server } = state
|
||||
const { uid } = authorize
|
||||
const { request } = server
|
||||
const circles: { [circleId: string]: Circle } = circle ? (circle.circleList || {}) : {}
|
||||
const userBelongCircles = circle ? (circle.userTies[ownProps.userId] ? circle.userTies[ownProps.userId].circleIdList : []) : []
|
||||
const isFollowed = userBelongCircles.length > 0
|
||||
return {
|
||||
circles: circles,
|
||||
userBelongCircles: userBelongCircles || [],
|
||||
isFollowed,
|
||||
circles,
|
||||
userBelongCircles,
|
||||
belongCirclesCount: userBelongCircles.length || 0,
|
||||
firstBelongCircle: userBelongCircles ? (circles ? circles[userBelongCircles[0]] : {}) : {},
|
||||
avatar: state.user.info && state.user.info[ownProps.userId] ? state.user.info[ownProps.userId].avatar || '' : '',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { User } from 'core/domain/users'
|
||||
import { UserFollower } from 'core/domain/circles'
|
||||
import { UserTie } from 'core/domain/circles'
|
||||
|
||||
export interface IUserBoxListComponentProps {
|
||||
|
||||
@@ -9,7 +9,7 @@ export interface IUserBoxListComponentProps {
|
||||
* @type {{[userId: string]: User}}
|
||||
* @memberof IUserBoxListComponentProps
|
||||
*/
|
||||
users: {[userId: string]: UserFollower}
|
||||
users: {[userId: string]: UserTie}
|
||||
|
||||
/**
|
||||
* User identifier
|
||||
|
||||
@@ -8,6 +8,7 @@ import { List } from 'material-ui/List'
|
||||
import CircleComponent from 'components/circle'
|
||||
import { IYourCirclesComponentProps } from './IYourCirclesComponentProps'
|
||||
import { IYourCirclesComponentState } from './IYourCirclesComponentState'
|
||||
import { Circle } from 'core/domain/circles';
|
||||
|
||||
// - Import API
|
||||
|
||||
@@ -97,10 +98,12 @@ const mapDispatchToProps = (dispatch: Function, ownProps: IYourCirclesComponentP
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IYourCirclesComponentProps) => {
|
||||
const {circle, authorize, server} = state
|
||||
const { uid } = state.authorize
|
||||
const circles: { [circleId: string]: Circle } = circle ? (circle.circleList || {}) : {}
|
||||
return {
|
||||
uid,
|
||||
circles: state.circle ? state.circle.userCircles[uid] : {}
|
||||
circles
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export enum CircleActionType {
|
||||
|
||||
|
||||
ADD_CIRCLE = 'ADD_CIRCLE',
|
||||
DELETE_CIRCLE = 'DELETE_CIRCLE',
|
||||
UPDATE_CIRCLE = 'UPDATE_CIRCLE',
|
||||
@@ -9,4 +9,13 @@ export enum CircleActionType {
|
||||
CLOSE_CIRCLE_SETTINGS = 'CLOSE_CIRCLE_SETTINGS',
|
||||
ADD_FOLLOWING_USER = 'ADD_FOLLOWING_USER',
|
||||
DELETE_FOLLOWING_USER = 'DELETE_FOLLOWING_USER',
|
||||
}
|
||||
UPDATE_USER_TIE = 'UPDATE_USER_TIE',
|
||||
ADD_USER_TIE_LIST = 'ADD_USER_TIE_LIST',
|
||||
ADD_USER_TIED_LIST = 'ADD_USER_TIED_LIST',
|
||||
DELETE_USER_FROM_CIRCLE = 'DELETE_USER_FROM_CIRCLE',
|
||||
SHOW_SELECT_CIRCLE_BOX = 'SHOW_SELECT_CIRCLE_BOX',
|
||||
HIDE_SELECT_CIRCLE_BOX = 'HIDE_SELECT_CIRCLE_BOX',
|
||||
SHOW_FOLLOWING_USER_LOADING = 'SHOW_FOLLOWING_USER_LOADING',
|
||||
HIDE_FOLLOWING_USER_LOADING = 'HIDE_FOLLOWING_USER_LOADING'
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
export enum PostActionType {
|
||||
|
||||
ADD_IMAGE_POST = 'ADD_IMAGE_POST',
|
||||
HAS_MORE_DATA_STREAM = 'HAS_MORE_DATA_STREAM',
|
||||
NOT_MORE_DATA_STREAM = 'NOT_MORE_DATA_STREAM',
|
||||
REQUEST_PAGE_STREAM = 'REQUEST_PAGE_STREAM',
|
||||
LAST_POST_STREAM = 'LAST_POST_STREAM',
|
||||
HAS_MORE_DATA_PROFILE = 'HAS_MORE_DATA_PROFILE',
|
||||
NOT_MORE_DATA_PROFILE = 'NOT_MORE_DATA_PROFILE',
|
||||
REQUEST_PAGE_PROFILE = 'REQUEST_PAGE_PROFILE',
|
||||
LAST_POST_PROFILE = 'LAST_POST_PROFILE',
|
||||
ADD_VIDEO_POST = 'ADD_VIDEO_POST',
|
||||
ADD_POST = 'ADD_POST',
|
||||
UPDATE_POST = 'UPDATE_POST',
|
||||
@@ -8,4 +16,3 @@
|
||||
ADD_LIST_POST = 'ADD_LIST_POST',
|
||||
CLEAR_ALL_DATA_POST = 'CLEAR_ALL_DATA_POST'
|
||||
}
|
||||
|
||||
|
||||
8
src/constants/serverActionType.ts
Normal file
8
src/constants/serverActionType.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export enum ServerActionType {
|
||||
|
||||
ADD_REQUEST = 'ADD_REQUEST',
|
||||
DELETE_REQUEST = 'DELETE_REQUEST',
|
||||
ERROR_REQUEST = 'ERROR_REQUEST',
|
||||
OK_REQUEST = 'OK_REQUEST',
|
||||
CLEAR_ALL_DATA_REQUEST = 'CLEAR_ALL_DATA_REQUEST'
|
||||
}
|
||||
6
src/constants/serverRequestType.ts
Normal file
6
src/constants/serverRequestType.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export enum ServerRequestType {
|
||||
CircleAddToCircle = 'CircleAddToCircle',
|
||||
CircleFollowUser = 'CircleFollowUser',
|
||||
CircleCreateTieUser = 'CircleCreateTieUser'
|
||||
|
||||
}
|
||||
@@ -7,5 +7,9 @@ export enum UserActionType {
|
||||
CLEAR_ALL_DATA_USER = 'CLEAR_ALL_DATA_USER',
|
||||
OPEN_EDIT_PROFILE = 'OPEN_EDIT_PROFILE',
|
||||
CLOSE_EDIT_PROFILE = 'CLOSE_EDIT_PROFILE',
|
||||
ADD_PEOPLE_INFO = 'ADD_PEOPLE_INFO'
|
||||
}
|
||||
ADD_PEOPLE_INFO = 'ADD_PEOPLE_INFO',
|
||||
HAS_MORE_DATA_PEOPLE = 'HAS_MORE_DATA_PEOPLE',
|
||||
NOT_MORE_DATA_PEOPLE = 'NOT_MORE_DATA_PEOPLE',
|
||||
REQUEST_PAGE_PEOPLE = 'REQUEST_PAGE_PEOPLE',
|
||||
LAST_USER_PEOPLE = 'LAST_POST_PEOPLE'
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { UserFollower } from './userFollower'
|
||||
import { BaseDomain } from 'core/domain/common'
|
||||
|
||||
export class Circle extends BaseDomain {
|
||||
@@ -35,12 +34,9 @@ export class Circle extends BaseDomain {
|
||||
*/
|
||||
public name: string
|
||||
|
||||
/**
|
||||
* The users in a circle
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof User
|
||||
*/
|
||||
public users: {[userId: string]: UserFollower}
|
||||
/**
|
||||
* Whether circle setting is open
|
||||
*/
|
||||
public openCircleSettings?: boolean
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {Circle} from './circle'
|
||||
import {UserFollower} from './userFollower'
|
||||
import { Circle } from './circle'
|
||||
import { UserTie } from './UserTie'
|
||||
|
||||
export {
|
||||
Circle,
|
||||
UserFollower
|
||||
}
|
||||
UserTie
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import { BaseDomain } from 'core/domain/common'
|
||||
|
||||
export class UserFollower extends BaseDomain {
|
||||
export class UserTie extends BaseDomain {
|
||||
|
||||
constructor (
|
||||
/**
|
||||
* User identifier
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof UserFollower
|
||||
* @memberof UserTie
|
||||
*/
|
||||
userId?: string
|
||||
public userId?: string,
|
||||
|
||||
/**
|
||||
* Circle creation date time
|
||||
@@ -16,30 +17,38 @@ export class UserFollower extends BaseDomain {
|
||||
* @type {Date}
|
||||
* @memberof Circle
|
||||
*/
|
||||
public creationDate?: number
|
||||
public creationDate?: number,
|
||||
|
||||
/**
|
||||
* User full name
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof UserFollower
|
||||
* @memberof UserTie
|
||||
*/
|
||||
public fullName: string
|
||||
public fullName?: string,
|
||||
|
||||
/**
|
||||
* Avatar URL address
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof UserFollower
|
||||
* @memberof UserTie
|
||||
*/
|
||||
public avatar: string
|
||||
public avatar?: string,
|
||||
|
||||
/**
|
||||
* If following user approved {true} or not {false}
|
||||
*
|
||||
* @type {Boolean}
|
||||
* @memberof UserFollower
|
||||
* @memberof UserTie
|
||||
*/
|
||||
public approved?: Boolean
|
||||
public approved?: Boolean,
|
||||
|
||||
/**
|
||||
* List of circles identifire which this user belong to
|
||||
*/
|
||||
public circleIdList?: string[]
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
}
|
||||
62
src/core/domain/graphs/graph.ts
Normal file
62
src/core/domain/graphs/graph.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { BaseDomain } from 'core/domain/common'
|
||||
|
||||
export class Graph extends BaseDomain {
|
||||
|
||||
constructor (
|
||||
/**
|
||||
* Left node of graph
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof Graph
|
||||
*/
|
||||
public leftNode: string,
|
||||
|
||||
/**
|
||||
* Graph relationship type
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof Graph
|
||||
*/
|
||||
public edgeType: string,
|
||||
|
||||
/**
|
||||
* Right node of graph
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof Graph
|
||||
*/
|
||||
public rightNode: string,
|
||||
|
||||
/**
|
||||
* Graph left node metadata
|
||||
*
|
||||
* @memberof Graph
|
||||
*/
|
||||
public LeftMetadata: any,
|
||||
|
||||
/**
|
||||
* Graph right node metadata
|
||||
*
|
||||
* @memberof Graph
|
||||
*/
|
||||
public rightMetadata: any,
|
||||
|
||||
/**
|
||||
* Graph metadata
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof Graph
|
||||
*/
|
||||
public graphMetadata: any,
|
||||
|
||||
/**
|
||||
* Graph node identifier
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof Graph
|
||||
*/
|
||||
public nodeId?: string
|
||||
|
||||
) { super() }
|
||||
|
||||
}
|
||||
5
src/core/domain/graphs/index.ts
Normal file
5
src/core/domain/graphs/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import {Graph} from './graph'
|
||||
|
||||
export {
|
||||
Graph
|
||||
}
|
||||
@@ -1,53 +1,53 @@
|
||||
import { BaseDomain } from 'core/domain/common'
|
||||
|
||||
export class User extends BaseDomain {
|
||||
|
||||
|
||||
/**
|
||||
* Full name of user
|
||||
*
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof User
|
||||
*/
|
||||
public fullName: string
|
||||
public fullName: string
|
||||
|
||||
/**
|
||||
* User avatar address
|
||||
*
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof User
|
||||
*/
|
||||
public avatar: string
|
||||
public avatar: string
|
||||
|
||||
/**
|
||||
* Email of the user
|
||||
*
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof User
|
||||
*/
|
||||
public email?: string | null
|
||||
public email?: string | null
|
||||
|
||||
/**
|
||||
* Password of the user
|
||||
*
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof User
|
||||
*/
|
||||
public password?: string | null
|
||||
public password?: string | null
|
||||
|
||||
/**
|
||||
* User identifier
|
||||
*
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof User
|
||||
*/
|
||||
public userId?: string | null
|
||||
|
||||
public userId?: string | null
|
||||
|
||||
/**
|
||||
* User creation date
|
||||
*
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof User
|
||||
*/
|
||||
public creationDate: number
|
||||
|
||||
}
|
||||
public creationDate: number
|
||||
|
||||
}
|
||||
|
||||
@@ -2,14 +2,6 @@ import { BaseDomain } from 'core/domain/common'
|
||||
|
||||
export class Vote extends BaseDomain {
|
||||
|
||||
/**
|
||||
* Vote identifier
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof Vote
|
||||
*/
|
||||
public id?: string | null
|
||||
|
||||
/**
|
||||
* Post identifire which vote on
|
||||
*
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//#region Interfaces
|
||||
|
||||
import { IServiceProvider } from 'core/factories'
|
||||
import { injectable } from 'inversify'
|
||||
import {
|
||||
IAuthorizeService,
|
||||
ICircleService,
|
||||
@@ -33,7 +34,7 @@ import {
|
||||
} from 'data/firestoreClient/services'
|
||||
|
||||
//#endregion
|
||||
|
||||
@injectable()
|
||||
export class ServiceProvide implements IServiceProvider {
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { User } from 'core/domain/users'
|
||||
import { Circle, UserFollower } from 'core/domain/circles'
|
||||
import { Circle, UserTie } from 'core/domain/circles'
|
||||
|
||||
/**
|
||||
* Circle service interface
|
||||
@@ -10,8 +10,6 @@ import { Circle, UserFollower } from 'core/domain/circles'
|
||||
export interface ICircleService {
|
||||
|
||||
addCircle: (userId: string, circle: Circle) => Promise<string>
|
||||
addFollowingUser: (userId: string, circleId: string, userCircle: User, userFollower: UserFollower, userFollowingId: string) => Promise<void>
|
||||
deleteFollowingUser: (userId: string, circleId: string,userFollowingId: string) => Promise<void>
|
||||
updateCircle: (userId: string, circleId: string, circle: Circle) => Promise<void>
|
||||
deleteCircle: (userId: string, circleId: string) => Promise<void>
|
||||
getCircles: (userId: string) => Promise<{ [circleId: string]: Circle }>
|
||||
|
||||
35
src/core/services/circles/IUserTieService.ts
Normal file
35
src/core/services/circles/IUserTieService.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { User, Profile } from 'core/domain/users'
|
||||
import { UserTie } from 'core/domain/circles'
|
||||
|
||||
/**
|
||||
* User tie service interface
|
||||
*
|
||||
* @export
|
||||
* @interface IUserTieService
|
||||
*/
|
||||
export interface IUserTieService {
|
||||
|
||||
/**
|
||||
* Tie users
|
||||
*/
|
||||
tieUseres: (userTieSenderInfo: UserTie, userTieReceiveInfo: UserTie, circleIds: string[])
|
||||
=> Promise<void>
|
||||
|
||||
/**
|
||||
* Remove users' tie
|
||||
*/
|
||||
removeUsersTie: (firstUserId: string, secondUserId: string)
|
||||
=> Promise<void>
|
||||
|
||||
/**
|
||||
* Get user ties
|
||||
*/
|
||||
getUserTies: (userId: string)
|
||||
=> Promise<{[userId: string]: UserTie}>
|
||||
|
||||
/**
|
||||
* Get the users who tied current user
|
||||
*/
|
||||
getUserTieSender: (userId: string)
|
||||
=> Promise<{[userId: string]: UserTie}>
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
import { ICircleService } from './ICircleService'
|
||||
import { IUserTieService } from './IUserTieService'
|
||||
|
||||
export {
|
||||
ICircleService
|
||||
ICircleService,
|
||||
IUserTieService
|
||||
}
|
||||
@@ -13,6 +13,6 @@ export interface ICommentService {
|
||||
addComment: (comment: Comment) => Promise<string>
|
||||
getComments: (postId: string, callback: (resultComments: { [postId: string]: { [commentId: string]: Comment } }) => void) => void
|
||||
updateComment: (comment: Comment) => Promise<void>
|
||||
deleteComment: (commentId: string, postId: string) => Promise<void>
|
||||
deleteComment: (commentId: string) => Promise<void>
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,17 @@ export interface IPostService {
|
||||
addPost: (post: Post) => Promise<string>
|
||||
updatePost: (post: Post) => Promise<void>
|
||||
deletePost: (postId: string) => Promise<void>
|
||||
getPosts: (userId: string) => Promise<{ [postId: string]: Post }>
|
||||
getPosts: (currentUserId: string,lastPostId: string, page: number, limit: number)
|
||||
=> Promise<{posts: {[postId: string]: Post }[], newLastPostId: string}>
|
||||
|
||||
/**
|
||||
* Get list of post by user identifier
|
||||
*/
|
||||
getPostsByUserId: (userId: string, lastPostId?: string, page?: number, limit?: number)
|
||||
=> Promise<{ posts: { [postId: string]: Post }[], newLastPostId: string }>
|
||||
|
||||
/**
|
||||
* Get post by the post identifier
|
||||
*/
|
||||
getPostById: (postId: string) => Promise<Post>
|
||||
}
|
||||
|
||||
@@ -9,5 +9,6 @@ import { User, Profile } from 'core/domain/users'
|
||||
export interface IUserService {
|
||||
getUserProfile: (userId: string) => Promise<Profile>
|
||||
updateUserProfile: (userId: string, profile: Profile) => Promise<void>
|
||||
getUsersProfile: (userId: string, lastKey?: string, numberOfItems?: number) => Promise<{[userId: string]: Profile}>
|
||||
getUsersProfile: (userId: string, lastUserId?: string, page?: number, limit?: number)
|
||||
=> Promise<{ users: { [userId: string]: Profile }[], newLastUserId: string }>
|
||||
}
|
||||
|
||||
@@ -10,5 +10,5 @@ import { Vote } from 'core/domain/votes'
|
||||
export interface IVoteService {
|
||||
addVote: (vote: Vote) => Promise<string>
|
||||
getVotes: (postId: string) => Promise<{[postId: string]: {[voteId: string]: Vote}}>
|
||||
deleteVote: (vote: Vote) => Promise<void>
|
||||
deleteVote: (userId: string, voteId: string) => Promise<void>
|
||||
}
|
||||
|
||||
17
src/core/socialProviderTypes.ts
Normal file
17
src/core/socialProviderTypes.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* InversifyJS need to use the type as identifiers at runtime.
|
||||
* We use symbols as identifiers but you can also use classes and or string literals.
|
||||
*/
|
||||
export const SocialProviderTypes = {
|
||||
AuthorizeService: Symbol('AuthorizeService'),
|
||||
UserTieService: Symbol('UserTieService'),
|
||||
CircleService: Symbol('CircleService'),
|
||||
CommentService: Symbol('CommentService'),
|
||||
CommonService: Symbol('CommonService'),
|
||||
StorageService: Symbol('StorageService'),
|
||||
ImageGalleryService: Symbol('ImageGalleryService'),
|
||||
NotificationService: Symbol('NotificationService'),
|
||||
PostService: Symbol('PostService'),
|
||||
UserService: Symbol('UserService'),
|
||||
VoteService: Symbol('VoteService')
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import firebase from 'firebase'
|
||||
try {
|
||||
let config = {
|
||||
apiKey: process.env.API_KEY,
|
||||
authDomain: process.env.AUTH_DOMAIN,
|
||||
databaseURL: process.env.DATABASE_URL,
|
||||
projectId: process.env.PROJECT_ID,
|
||||
storageBucket: process.env.STORAGE_BUCKET,
|
||||
messagingSenderId: process.env.MESSAGING_SENDER_ID
|
||||
}
|
||||
|
||||
firebase.initializeApp(config)
|
||||
} catch (error) {
|
||||
console.log('=========Firebase initializer==============')
|
||||
console.log(error)
|
||||
console.log('====================================')
|
||||
}
|
||||
|
||||
// - Storage reference
|
||||
export let storageRef = firebase.storage().ref()
|
||||
|
||||
// - Database authorize
|
||||
export let firebaseAuth = firebase.auth
|
||||
export let firebaseRef = firebase.database().ref()
|
||||
|
||||
// - Firebase default
|
||||
export default firebase
|
||||
@@ -1,266 +0,0 @@
|
||||
import moment from 'moment'
|
||||
|
||||
import { Profile } from 'core/domain/users'
|
||||
|
||||
// - Import react components
|
||||
import { firebaseRef, firebaseAuth } from 'data/firebaseClient'
|
||||
|
||||
import { IAuthorizeService } from 'core/services/authorize'
|
||||
import { User, UserProvider } from 'core/domain/users'
|
||||
import { LoginUser, RegisterUserResult } from 'core/domain/authorize'
|
||||
import { SocialError } from 'core/domain/common'
|
||||
|
||||
import { OAuthType } from 'core/domain/authorize/oauthType'
|
||||
/**
|
||||
* Firbase authorize service
|
||||
*
|
||||
* @export
|
||||
* @class AuthorizeService
|
||||
* @implements {IAuthorizeService}
|
||||
*/
|
||||
export class AuthorizeService implements IAuthorizeService {
|
||||
|
||||
/**
|
||||
* Login the user
|
||||
*
|
||||
* @returns {Promise<LoginUser>}
|
||||
* @memberof IAuthorizeService
|
||||
*/
|
||||
public login: (email: string, password: string) => Promise<LoginUser> = (email, password) => {
|
||||
|
||||
return new Promise<LoginUser>((resolve, reject) => {
|
||||
firebaseAuth()
|
||||
.signInWithEmailAndPassword(email, password)
|
||||
.then((result) => {
|
||||
resolve(new LoginUser(result.uid, result.emailVerified))
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs out the user
|
||||
*
|
||||
* @returns {Promise<void>}
|
||||
* @memberof IAuthorizeService
|
||||
*/
|
||||
public logout: () => Promise<void> = () => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
firebaseAuth()
|
||||
.signOut()
|
||||
.then((result) => {
|
||||
resolve()
|
||||
})
|
||||
.catch((error: any) => {
|
||||
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a user
|
||||
*
|
||||
* @returns {Promise<void>}
|
||||
* @memberof IAuthorizeService
|
||||
*/
|
||||
public registerUser: (user: User) => Promise<RegisterUserResult> = (user) => {
|
||||
return new Promise<RegisterUserResult>((resolve, reject) => {
|
||||
firebaseAuth()
|
||||
.createUserWithEmailAndPassword(user.email as string, user.password as string)
|
||||
.then((signupResult) => {
|
||||
const {uid, email} = signupResult
|
||||
this.storeUserInformation(uid,email,user.fullName,'').then(resolve)
|
||||
})
|
||||
.catch((error: any) => reject(new SocialError(error.code, error.message)))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user password
|
||||
*
|
||||
* @returns {Promise<void>}
|
||||
* @memberof IAuthorizeService
|
||||
*/
|
||||
public updatePassword: (newPassword: string) => Promise<void> = (newPassword) => {
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
let user = firebaseAuth().currentUser
|
||||
if (user) {
|
||||
user.updatePassword(newPassword).then(() => {
|
||||
// Update successful.
|
||||
resolve()
|
||||
}).catch((error: any) => {
|
||||
// An error happened.
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* On user authorization changed event
|
||||
*
|
||||
* @memberof IAuthorizeService
|
||||
*/
|
||||
public onAuthStateChanged: (callBack: (isVerifide: boolean, user: User) => void) => any = (callBack) => {
|
||||
firebaseAuth().onAuthStateChanged( (user: any) => {
|
||||
let isVerifide = false
|
||||
if (user) {
|
||||
if (user.emailVerified || user.providerData[0].providerId.trim() !== 'password') {
|
||||
isVerifide = true
|
||||
} else {
|
||||
isVerifide = false
|
||||
}
|
||||
}
|
||||
callBack(isVerifide,user)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset user password
|
||||
*
|
||||
* @memberof AuthorizeService
|
||||
*/
|
||||
public resetPassword: (email: string) => Promise<void> = (email) => {
|
||||
return new Promise<void>((resolve,reject) => {
|
||||
let auth = firebaseAuth()
|
||||
|
||||
auth.sendPasswordResetEmail(email).then(function () {
|
||||
resolve()
|
||||
}).catch((error: any) => {
|
||||
// An error happened.
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Send verfication email to user email
|
||||
*
|
||||
* @memberof AuthorizeService
|
||||
*/
|
||||
public sendEmailVerification: () => Promise<void> = () => {
|
||||
return new Promise<void>((resolve,reject) => {
|
||||
let auth = firebaseAuth()
|
||||
const user = auth.currentUser
|
||||
|
||||
if (user) {
|
||||
user.sendEmailVerification().then(() => {
|
||||
resolve()
|
||||
}).catch((error: any) => {
|
||||
// An error happened.
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
} else {
|
||||
reject(new SocialError('authorizeService/nullException', 'User was null!'))
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
public loginWithOAuth: (type: OAuthType) => Promise<LoginUser> = (type) => {
|
||||
return new Promise<LoginUser>((resolve,reject) => {
|
||||
|
||||
let provider: any
|
||||
|
||||
switch (type) {
|
||||
case OAuthType.GITHUB:
|
||||
provider = new firebaseAuth.GithubAuthProvider()
|
||||
break
|
||||
case OAuthType.FACEBOOK:
|
||||
provider = new firebaseAuth.FacebookAuthProvider()
|
||||
break
|
||||
case OAuthType.GOOGLE:
|
||||
provider = new firebaseAuth.GoogleAuthProvider()
|
||||
break
|
||||
default:
|
||||
throw new SocialError('authorizeService/loginWithOAuth','None of OAuth type is matched!')
|
||||
}
|
||||
firebaseAuth().signInWithPopup(provider).then((result) => {
|
||||
// This gives you a GitHub Access Token. You can use it to access the GitHub API.
|
||||
let token = result.credential.accessToken
|
||||
// The signed-in user info.
|
||||
const {user} = result
|
||||
const {credential} = result
|
||||
const {uid, displayName, email, photoURL} = user
|
||||
const {accessToken, provider, providerId} = credential
|
||||
|
||||
this.storeUserProviderData(uid,email,displayName,photoURL,providerId,provider,accessToken)
|
||||
// this.storeUserInformation(uid,email,displayName,photoURL).then(resolve)
|
||||
resolve(new LoginUser(user.uid,true,providerId,displayName,email,photoURL))
|
||||
|
||||
}).catch(function (error: any) {
|
||||
// Handle Errors here.
|
||||
let errorCode = error.code
|
||||
let errorMessage = error.message
|
||||
// The email of the user's account used.
|
||||
let email = error.email
|
||||
// The firebase.auth.AuthCredential type that was used.
|
||||
let credential = error.credential
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Store user information
|
||||
*
|
||||
* @private
|
||||
* @memberof AuthorizeService
|
||||
*/
|
||||
private storeUserInformation = (userId: string, email: string, fullName: string, avatar: string) => {
|
||||
return new Promise<RegisterUserResult>((resolve,reject) => {
|
||||
firebaseRef.child(`users/${userId}/info`)
|
||||
.set(new Profile(
|
||||
avatar,
|
||||
fullName,
|
||||
'',
|
||||
'',
|
||||
moment().unix(),
|
||||
email
|
||||
))
|
||||
.then((result) => {
|
||||
resolve(new RegisterUserResult(userId))
|
||||
})
|
||||
.catch((error: any) => reject(new SocialError(error.name, error.message)))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Store user provider information
|
||||
*
|
||||
* @private
|
||||
* @memberof AuthorizeService
|
||||
*/
|
||||
private storeUserProviderData = (
|
||||
userId: string,
|
||||
email: string,
|
||||
fullName: string,
|
||||
avatar: string,
|
||||
providerId: string,
|
||||
provider: string,
|
||||
accessToken: string
|
||||
) => {
|
||||
return new Promise<RegisterUserResult>((resolve,reject) => {
|
||||
firebaseRef.child(`users/${userId}/providerInfo`)
|
||||
.set(new UserProvider(
|
||||
userId,
|
||||
email,
|
||||
fullName,
|
||||
avatar,
|
||||
providerId,
|
||||
provider,
|
||||
accessToken
|
||||
))
|
||||
.then((result) => {
|
||||
resolve(new RegisterUserResult(userId))
|
||||
})
|
||||
.catch((error: any) => reject(new SocialError(error.name, error.message)))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { AuthorizeService } from './AuthorizeService'
|
||||
|
||||
export {
|
||||
AuthorizeService
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
// - Import react components
|
||||
import { firebaseRef, firebaseAuth, db } from 'data/firebaseClient'
|
||||
|
||||
import { SocialError } from 'core/domain/common'
|
||||
import { ICircleService } from 'core/services/circles'
|
||||
import { Circle, UserFollower } from 'core/domain/circles'
|
||||
import { User } from 'core/domain/users'
|
||||
|
||||
/**
|
||||
* Firbase circle service
|
||||
*
|
||||
* @export
|
||||
* @class CircleService
|
||||
* @implements {ICircleService}
|
||||
*/
|
||||
export class CircleService implements ICircleService {
|
||||
|
||||
public addCircle: (userId: string, circle: Circle)
|
||||
=> Promise<string> = (userId, circle) => {
|
||||
return new Promise<string>((resolve,reject) => {
|
||||
|
||||
let circleRef = firebaseRef.child(`users/${userId}/circles`).push(circle)
|
||||
circleRef.then(() => {
|
||||
resolve(circleRef.key as string)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
public addFollowingUser: (userId: string, circleId: string, userCircle: User, userFollower: UserFollower, userFollowingId: string)
|
||||
=> Promise<void> = (userId, circleId, userCircle, userFollower, userFollowingId) => {
|
||||
return new Promise<void>((resolve,reject) => {
|
||||
|
||||
let updates: any = {}
|
||||
updates[`users/${userId}/circles/${circleId}/users/${userFollowingId}`] = userCircle
|
||||
updates[`users/${userFollowingId}/circles/-Followers/users/${userId}`] = userFollower
|
||||
|
||||
firebaseRef.update(updates).then(() => {
|
||||
resolve()
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
public deleteFollowingUser: (userId: string, circleId: string, userFollowingId: string)
|
||||
=> Promise<void> = (userId, circleId, userFollowingId) => {
|
||||
return new Promise<void>((resolve,reject) => {
|
||||
|
||||
let updates: any = {}
|
||||
updates[`users/${userId}/circles/${circleId}/users/${userFollowingId}`] = null
|
||||
updates[`users/${userFollowingId}/circles/-Followers/users/${userId}`] = null
|
||||
|
||||
firebaseRef.update(updates).then(() => {
|
||||
resolve()
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
public updateCircle: (userId: string, circleId: string, circle: Circle)
|
||||
=> Promise<void> = (userId, circleId, circle) => {
|
||||
return new Promise<void>((resolve,reject) => {
|
||||
|
||||
let updates: any = {}
|
||||
updates[`users/${userId}/circles/${circleId}`] = circle
|
||||
firebaseRef.update(updates).then(() => {
|
||||
resolve()
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
public deleteCircle: (userId: string, circleId: string)
|
||||
=> Promise<void> = (userId, circleId) => {
|
||||
return new Promise<void>((resolve,reject) => {
|
||||
|
||||
let updates: any = {}
|
||||
updates[`users/${userId}/circles/${circleId}`] = null
|
||||
firebaseRef.update(updates).then(() => {
|
||||
resolve()
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
public getCircles: (userId: string) => Promise<{ [circleId: string]: Circle }> = (userId) => {
|
||||
return new Promise<{ [circleId: string]: Circle }>((resolve,reject) => {
|
||||
let circlesRef: any = firebaseRef.child(`users/${userId}/circles`)
|
||||
|
||||
circlesRef.once('value').then((snapshot: any) => {
|
||||
let circles: any = snapshot.val() || {}
|
||||
let parsedCircles: { [circleId: string]: Circle } = {}
|
||||
Object.keys(circles).forEach((circleId) => {
|
||||
|
||||
parsedCircles[circleId] = {
|
||||
id: circleId,
|
||||
...circles[circleId]
|
||||
}
|
||||
})
|
||||
resolve(parsedCircles)
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { CircleService } from './CircleService'
|
||||
|
||||
export {
|
||||
CircleService
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
// - Import react components
|
||||
import { firebaseRef, firebaseAuth } from 'data/firebaseClient'
|
||||
|
||||
import { SocialError } from 'core/domain/common'
|
||||
import { ICommentService } from 'core/services/comments'
|
||||
import { Comment } from 'core/domain/comments'
|
||||
|
||||
/**
|
||||
* Firbase comment service
|
||||
*
|
||||
* @export
|
||||
* @class CommentService
|
||||
* @implements {ICommentService}
|
||||
*/
|
||||
export class CommentService implements ICommentService {
|
||||
public addComment: (postId: string, comment: Comment)
|
||||
=> Promise<string> = (postId, comment) => {
|
||||
return new Promise<string>((resolve,reject) => {
|
||||
let commentRef: any = firebaseRef.child(`postComments/${postId}`).push(comment)
|
||||
commentRef.then(() => {
|
||||
resolve(commentRef.key)
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code,error.message))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
public getComments: (callback: (resultComments: { [postId: string]: { [commentId: string]: Comment } }) => void)
|
||||
=> void = (callback) => {
|
||||
let commentsRef: any = firebaseRef.child(`postComments`)
|
||||
commentsRef.on('value', (snapshot: any) => {
|
||||
let comments: {[postId: string]: {[commentId: string]: Comment}} = snapshot!.val() || {}
|
||||
callback(comments)
|
||||
})
|
||||
}
|
||||
|
||||
public updateComment: (commentId: string, postId: string, comment: Comment)
|
||||
=> Promise<void> = (commentId, postId, comment) => {
|
||||
return new Promise<void>((resolve,reject) => {
|
||||
|
||||
let updates: any = {}
|
||||
updates[`postComments/${postId}/${commentId}`] = comment
|
||||
firebaseRef.update(updates)
|
||||
.then(() => {
|
||||
resolve()
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code,error.message))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
public deleteComment: (commentId: string, postId: string)
|
||||
=> Promise<void> = (commentId, postId) => {
|
||||
return new Promise<void>((resolve,reject) => {
|
||||
|
||||
let updates: any = {}
|
||||
updates[`postComments/${postId}/${commentId}`] = null
|
||||
firebaseRef.update(updates)
|
||||
.then(() => {
|
||||
resolve()
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code,error.message))
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { CommentService } from './CommentService'
|
||||
|
||||
export {
|
||||
CommentService
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// - Import react components
|
||||
import { firebaseRef, firebaseAuth } from 'data/firebaseClient'
|
||||
|
||||
import { SocialError } from 'core/domain/common'
|
||||
import { ICommonService } from 'core/services/common'
|
||||
|
||||
/**
|
||||
* Firbase common service
|
||||
*
|
||||
* @export
|
||||
* @class CommonService
|
||||
* @implements {ICommonService}
|
||||
*/
|
||||
export class CommonService implements ICommonService {
|
||||
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { CommonService } from './CommonService'
|
||||
|
||||
export {
|
||||
CommonService
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import { storageRef } from 'data/firebaseClient'
|
||||
import { IStorageService } from 'core/services/files'
|
||||
import { FileResult } from 'models/files/fileResult'
|
||||
|
||||
export class StorageService implements IStorageService {
|
||||
|
||||
/**
|
||||
* Upload image on the server
|
||||
* @param {file} file
|
||||
* @param {string} fileName
|
||||
*/
|
||||
public uploadFile = (file: any, fileName: string, progress: (percentage: number, status: boolean) => void) => {
|
||||
|
||||
return new Promise<FileResult>((resolve, reject) => {
|
||||
// Create a storage refrence
|
||||
let storegeFile = storageRef.child(`images/${fileName}`)
|
||||
|
||||
// Upload file
|
||||
let task = storegeFile.put(file)
|
||||
task.then((result) => {
|
||||
resolve(new FileResult(result.downloadURL!,result.metadata.fullPath))
|
||||
}).catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
|
||||
// Upload storage bar
|
||||
task.on('state_changed', (snapshot: any) => {
|
||||
let percentage: number = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
|
||||
progress(percentage, true)
|
||||
}, (error) => {
|
||||
console.log('========== Upload Image ============')
|
||||
console.log(error)
|
||||
console.log('====================================')
|
||||
|
||||
}, () => {
|
||||
progress(100, false)
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { StorageService } from './StorageService'
|
||||
|
||||
export {
|
||||
StorageService
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
import { FileResult } from 'models/files/fileResult'
|
||||
// - Import react components
|
||||
import { firebaseRef, firebaseAuth, storageRef } from 'data/firebaseClient'
|
||||
|
||||
import { SocialError } from 'core/domain/common'
|
||||
import { IImageGalleryService } from 'core/services/imageGallery'
|
||||
import { Image } from 'core/domain/imageGallery'
|
||||
import { IStorageService } from 'core/services/files'
|
||||
import { IServiceProvider, ServiceProvide } from 'core/factories'
|
||||
|
||||
/**
|
||||
* Firbase image gallery service
|
||||
*
|
||||
* @export
|
||||
* @class ImageGalleryService
|
||||
* @implements {IImageGalleryService}
|
||||
*/
|
||||
export class ImageGalleryService implements IImageGalleryService {
|
||||
|
||||
private readonly storageService: IStorageService
|
||||
private readonly serviceProvider: IServiceProvider
|
||||
|
||||
constructor () {
|
||||
this.serviceProvider = new ServiceProvide()
|
||||
this.storageService = this.serviceProvider.createStorageService()
|
||||
}
|
||||
|
||||
public getImageGallery: (userId: string)
|
||||
=> Promise<Image[]> = (userId) => {
|
||||
return new Promise<Image[]>((resolve,reject) => {
|
||||
let imagesRef: any = firebaseRef.child(`userFiles/${userId}/files/images`)
|
||||
|
||||
imagesRef.once('value').then((snapshot: any) => {
|
||||
let images = snapshot.val() || {}
|
||||
let parsedImages: Image[] = []
|
||||
Object.keys(images).forEach((imageId) => {
|
||||
parsedImages.push({
|
||||
id: imageId,
|
||||
...images[imageId]
|
||||
})
|
||||
})
|
||||
resolve(parsedImages)
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
public saveImage: (userId: string, image: Image)
|
||||
=> Promise<string> = (userId, image) => {
|
||||
return new Promise<string>((resolve,reject) => {
|
||||
|
||||
let imageRef = firebaseRef.child(`userFiles/${userId}/files/images`).push(image)
|
||||
imageRef.then(() => {
|
||||
resolve(imageRef.key!)
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
public deleteImage: (userId: string, imageId: string)
|
||||
=> Promise<void> = (userId, imageId) => {
|
||||
return new Promise<void>((resolve,reject) => {
|
||||
|
||||
let updates: any = {}
|
||||
updates[`userFiles/${userId}/files/images/${imageId}`] = null
|
||||
|
||||
firebaseRef.update(updates).then(() => {
|
||||
resolve()
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
public uploadImage: (image: any, imageName: string, progressCallback: (percentage: number, status: boolean) => void)
|
||||
=> Promise<FileResult> = (image, imageName, progressCallback) => {
|
||||
return new Promise<FileResult>((resolve,reject) => {
|
||||
this.storageService.uploadFile(image,imageName,progressCallback)
|
||||
.then((result: FileResult) => {
|
||||
resolve(result)
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
public downloadImage: (fileName: string)
|
||||
=> Promise<string> = (fileName) => {
|
||||
return new Promise<string>((resolve,reject) => {
|
||||
|
||||
// Create a reference to the file we want to download
|
||||
let starsRef: any = storageRef.child(`images/${fileName}`)
|
||||
|
||||
// Get the download URL
|
||||
starsRef.getDownloadURL().then((url: string) => {
|
||||
resolve(url)
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { ImageGalleryService } from './ImageGalleryService'
|
||||
|
||||
export {
|
||||
ImageGalleryService
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import { AuthorizeService } from './authorize'
|
||||
import { CircleService } from './circles'
|
||||
import { CommentService } from './comments'
|
||||
import { CommonService } from './common'
|
||||
import { ImageGalleryService } from './imageGallery'
|
||||
import { NotificationService } from './notifications'
|
||||
import { PostService } from './posts'
|
||||
import { UserService } from './users'
|
||||
import { VoteService } from './votes'
|
||||
import { StorageService } from './files'
|
||||
|
||||
export {
|
||||
AuthorizeService,
|
||||
CircleService,
|
||||
CommentService,
|
||||
CommonService,
|
||||
ImageGalleryService,
|
||||
NotificationService,
|
||||
PostService,
|
||||
UserService,
|
||||
VoteService,
|
||||
StorageService
|
||||
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { NotificationService } from './NotificationService'
|
||||
|
||||
export {
|
||||
NotificationService
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
// - Import react components
|
||||
import { firebaseRef, firebaseAuth } from 'data/firebaseClient'
|
||||
|
||||
import { SocialError } from 'core/domain/common'
|
||||
import { Notification } from 'core/domain/notifications'
|
||||
import { INotificationService } from 'core/services/notifications'
|
||||
|
||||
/**
|
||||
* Firbase notification service
|
||||
*
|
||||
* @export
|
||||
* @class NotificationService
|
||||
* @implements {INotificationService}
|
||||
*/
|
||||
export class NotificationService implements INotificationService {
|
||||
public addNotification: (notification: Notification)
|
||||
=> Promise<void> = (notification: Notification) => {
|
||||
return new Promise<void>((resolve,reject) => {
|
||||
firebaseRef.child(`userNotifies/${notification.notifyRecieverUserId}`)
|
||||
.push(notification)
|
||||
.then(() => {
|
||||
resolve()
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
public getNotifications: (userId: string, callback: (resultNotifications: {[notifyId: string]: Notification}) => void)
|
||||
=> void = (userId,callback) => {
|
||||
let notificationsRef = firebaseRef.child(`userNotifies/${userId}`)
|
||||
notificationsRef.on('value', (snapshot: any) => {
|
||||
let notifications: {[notifyId: string]: Notification} = snapshot.val() || {}
|
||||
callback(notifications)
|
||||
})
|
||||
}
|
||||
|
||||
public deleteNotification: (notificationId: string, userId: string)
|
||||
=> Promise < void > = (notificationId, userId) => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
let updates: any = {}
|
||||
updates[`userNotifies/${userId}/${notificationId}`] = null
|
||||
firebaseRef.update(updates)
|
||||
.then(() => {
|
||||
resolve()
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
public setSeenNotification: (notificationId: string, userId: string, notification: Notification)
|
||||
=> Promise <void> = (notificationId, userId, notification) => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
let updates: any = {}
|
||||
updates[`userNotifies/${userId}/${notificationId}`] = notification
|
||||
firebaseRef.update(updates)
|
||||
.then(() => {
|
||||
resolve()
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
// - Import react components
|
||||
import { firebaseRef, firebaseAuth } from 'data/firebaseClient'
|
||||
|
||||
import { SocialError } from 'core/domain/common'
|
||||
import { Post } from 'core/domain/posts'
|
||||
import { IPostService } from 'core/services/posts'
|
||||
|
||||
/**
|
||||
* Firbase post service
|
||||
*
|
||||
* @export
|
||||
* @class PostService
|
||||
* @implements {IPostService}
|
||||
*/
|
||||
export class PostService implements IPostService {
|
||||
|
||||
public addPost: (userId: string, post: Post)
|
||||
=> Promise<string> = (userId, post) => {
|
||||
return new Promise<string>((resolve,reject) => {
|
||||
let postRef: any = firebaseRef.child(`users/${userId}/posts`).push(post)
|
||||
postRef.then(() => {
|
||||
resolve(postRef.key)
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code,error.message))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
public updatePost: (userId: string, postId: string, post: Post)
|
||||
=> Promise<void> = (userId, postId, post) => {
|
||||
return new Promise<void>((resolve,reject) => {
|
||||
let updates: any = {}
|
||||
updates[`users/${userId}/posts/${postId}`] = post
|
||||
firebaseRef.update(updates).then(() => {
|
||||
resolve()
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code,error.message))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
public deletePost: (userId: string, postId: string)
|
||||
=> Promise<void> = (userId, postId) => {
|
||||
return new Promise<void>((resolve,reject) => {
|
||||
let updates: any = {}
|
||||
updates[`users/${userId}/posts/${postId}`] = null
|
||||
firebaseRef.update(updates).then(() => {
|
||||
resolve()
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code,error.message))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
public getPosts: (userId: string)
|
||||
=> Promise<{ [postId: string]: Post }> = (userId) => {
|
||||
return new Promise<{ [postId: string]: Post }>((resolve,reject) => {
|
||||
|
||||
let postsRef: any = firebaseRef.child(`users/${userId}/posts`)
|
||||
postsRef.once('value').then((snapshot: any) => {
|
||||
let posts: any = snapshot.val() || {}
|
||||
let parsedPosts: { [postId: string]: Post } = {}
|
||||
|
||||
Object.keys(posts).forEach((postId) => {
|
||||
parsedPosts[postId] = {
|
||||
id: postId,
|
||||
...posts[postId]
|
||||
}
|
||||
})
|
||||
resolve(parsedPosts)
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code,error.message))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
public getPostById: (userId: string, postId: string)
|
||||
=> Promise<Post> = (userId, postId) => {
|
||||
return new Promise<Post>((resolve,reject) => {
|
||||
|
||||
let postsRef: any = firebaseRef.child(`users/${userId}/posts/${postId}`)
|
||||
|
||||
postsRef.once('value').then((snapshot: any) => {
|
||||
let newPost = snapshot.val() || {}
|
||||
let post: Post = {
|
||||
id: postId,
|
||||
...newPost
|
||||
}
|
||||
resolve(post)
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code,error.message))
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { PostService } from './PostService'
|
||||
|
||||
export {
|
||||
PostService
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
// - Import react components
|
||||
import { firebaseRef, firebaseAuth } from 'data/firebaseClient'
|
||||
import moment from 'moment'
|
||||
|
||||
import { SocialError } from 'core/domain/common'
|
||||
import { Profile, UserProvider } from 'core/domain/users'
|
||||
import { IUserService } from 'core/services/users'
|
||||
|
||||
/**
|
||||
* Firbase user service
|
||||
*
|
||||
* @export
|
||||
* @class UserService
|
||||
* @implements {IUserService}
|
||||
*/
|
||||
export class UserService implements IUserService {
|
||||
|
||||
public getUserProfile: (userId: string)
|
||||
=> Promise<Profile> = (userId) => {
|
||||
return new Promise<Profile>((resolve, reject) => {
|
||||
let userProfileRef: any = firebaseRef.child(`users/${userId}/info`)
|
||||
|
||||
userProfileRef.once('value').then((snapshot: any) => {
|
||||
let userProfile: Profile = snapshot.val() || {}
|
||||
if (Object.keys(userProfile).length === 0 && userProfile.constructor === Object) {
|
||||
this.getUserProviderData(userId).then((providerData: UserProvider) => {
|
||||
const {avatar,fullName, email} = providerData
|
||||
const userProfile = new Profile(avatar,fullName,'','', moment().unix(),email)
|
||||
resolve(userProfile)
|
||||
this.updateUserProfile(userId,userProfile)
|
||||
})
|
||||
} else {
|
||||
resolve(userProfile)
|
||||
}
|
||||
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
public updateUserProfile: (userId: string, profile: Profile)
|
||||
=> Promise<void> = (userId, profile) => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
let updates: any = {}
|
||||
|
||||
updates[`users/${userId}/info`] = profile
|
||||
firebaseRef.update(updates).then(() => {
|
||||
resolve()
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
})
|
||||
}
|
||||
public getUsersProfile: (userId: string, page?: number, lastKey?: string)
|
||||
=> Promise<{ [userId: string]: Profile }> = (userId, page, lastKey) => {
|
||||
return new Promise<{ [userId: string]: Profile }>((resolve, reject) => {
|
||||
let usersProfileRef: any
|
||||
if (page) {
|
||||
const numberOfItems = (page * 12) + 12
|
||||
usersProfileRef = firebaseRef.child(`users`).orderByKey().startAt(lastKey!).limitToFirst(numberOfItems)
|
||||
} else {
|
||||
usersProfileRef = firebaseRef.child(`users`).orderByKey()
|
||||
}
|
||||
|
||||
usersProfileRef.once('value').then((snapshot: any) => {
|
||||
let usersProfile: any = snapshot.val() || {}
|
||||
let parsedusersProfile: { [userId: string]: Profile } = {}
|
||||
Object.keys(usersProfile).forEach((userKey) => {
|
||||
if (userId !== userKey) {
|
||||
let userInfo = usersProfile[userKey].info
|
||||
parsedusersProfile[userKey] = {
|
||||
avatar: userInfo.avatar,
|
||||
email: userInfo.email,
|
||||
fullName: userInfo.fullName,
|
||||
banner: userInfo.banner,
|
||||
tagLine: userInfo.tagLine
|
||||
}
|
||||
}
|
||||
})
|
||||
resolve(parsedusersProfile)
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
private getUserProviderData = (userId: string) => {
|
||||
return new Promise<UserProvider>((resolve,reject) => {
|
||||
let userProviderRef: any = firebaseRef.child(`users/${userId}/providerInfo`)
|
||||
userProviderRef.once('value').then((snapshot: any) => {
|
||||
let userProviderRef: any = firebaseRef.child(`users/${userId}/info`)
|
||||
let userProvider: UserProvider = snapshot.val() || {}
|
||||
console.log('----------------userProfile')
|
||||
console.log(userProvider)
|
||||
console.log('-----------------------')
|
||||
resolve(userProvider)
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { UserService } from './UserService'
|
||||
|
||||
export {
|
||||
UserService
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
// - Import react components
|
||||
import { firebaseRef, firebaseAuth } from 'data/firebaseClient'
|
||||
|
||||
import { SocialError } from 'core/domain/common'
|
||||
import { Vote } from 'core/domain/votes'
|
||||
import { IVoteService } from 'core/services/votes'
|
||||
|
||||
/**
|
||||
* Firbase vote service
|
||||
*
|
||||
* @export
|
||||
* @class VoteService
|
||||
* @implements {IVoteService}
|
||||
*/
|
||||
export class VoteService implements IVoteService {
|
||||
|
||||
public addVote: (vote: Vote)
|
||||
=> Promise<string> = (vote) => {
|
||||
return new Promise<string>((resolve,reject) => {
|
||||
let voteRef = firebaseRef.child(`postVotes/${vote.postId}`)
|
||||
.push(vote)
|
||||
voteRef.then(() => {
|
||||
resolve(voteRef.key!)
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code,error.message))
|
||||
})
|
||||
})
|
||||
}
|
||||
public getVotes: ()
|
||||
=> Promise<{ [postId: string]: { [voteId: string]: Vote } }> = () => {
|
||||
return new Promise<{ [postId: string]: { [voteId: string]: Vote } }>((resolve,reject) => {
|
||||
let votesRef: any = firebaseRef.child(`postVotes`)
|
||||
|
||||
votesRef.on('value',(snapshot: any) => {
|
||||
let postVotes: {[postId: string]: {[voteId: string]: Vote}} = snapshot.val() || {}
|
||||
resolve(postVotes)
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
public deleteVote: (voteId: string, postId: string)
|
||||
=> Promise<void> = (voteId, postId) => {
|
||||
return new Promise<void>((resolve,reject) => {
|
||||
let updates: any = {}
|
||||
updates[`postVotes/${postId}/${voteId}`] = null
|
||||
firebaseRef.update(updates).then(() => {
|
||||
resolve()
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code,error.message))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
49
src/data/firestoreClient/dependecyRegisterar.ts
Normal file
49
src/data/firestoreClient/dependecyRegisterar.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { GraphService } from './services/graphs/GraphService'
|
||||
import { IGraphService } from './services/graphs/IGraphService'
|
||||
import { VoteService } from './services/votes/VoteService'
|
||||
import { PostService } from './services/posts/PostService'
|
||||
import { StorageService } from './services/files/StorageService'
|
||||
import { CommonService } from './services/common/CommonService'
|
||||
import { CommentService } from './services/comments/CommentService'
|
||||
import { ICircleService } from 'core/services/circles/ICircleService'
|
||||
import { Container } from 'inversify'
|
||||
import { IUserService } from 'core/services/users'
|
||||
import { SocialProviderTypes } from 'core/socialProviderTypes'
|
||||
import { UserService } from './services/users/UserService'
|
||||
import { IAuthorizeService } from 'core/services/authorize'
|
||||
import { AuthorizeService } from './services/authorize/AuthorizeService'
|
||||
import { CircleService } from './services/circles/CircleService'
|
||||
import { ICommentService } from 'core/services/comments'
|
||||
import { ICommonService } from 'core/services/common'
|
||||
import { IStorageService } from 'core/services/files'
|
||||
import { IImageGalleryService } from 'core/services/imageGallery'
|
||||
import { INotificationService } from 'core/services/notifications'
|
||||
import { IPostService } from 'core/services/posts'
|
||||
import { IVoteService } from 'core/services/votes'
|
||||
import { ImageGalleryService } from './services/imageGallery/ImageGalleryService'
|
||||
import { NotificationService } from './services/notifications/NotificationService'
|
||||
import { FirestoreClientTypes } from './firestoreClientTypes'
|
||||
import { IUserTieService } from 'core/services/circles'
|
||||
import { UserTieService } from './services/circles/UserTieService'
|
||||
|
||||
/**
|
||||
* Register firestore client dependecies
|
||||
* @param container DI container
|
||||
*/
|
||||
export const useFirestore = (container: Container) => {
|
||||
container.bind<IAuthorizeService>(SocialProviderTypes.AuthorizeService).to(AuthorizeService)
|
||||
container.bind<ICircleService>(SocialProviderTypes.CircleService).to(CircleService)
|
||||
container.bind<ICommentService>(SocialProviderTypes.CommentService).to(CommentService)
|
||||
container.bind<ICommonService>(SocialProviderTypes.CommonService).to(CommonService)
|
||||
container.bind<IStorageService>(SocialProviderTypes.StorageService).to(StorageService)
|
||||
container.bind<IImageGalleryService>(SocialProviderTypes.ImageGalleryService).to(ImageGalleryService)
|
||||
container.bind<INotificationService>(SocialProviderTypes.NotificationService).to(NotificationService)
|
||||
container.bind<IPostService>(SocialProviderTypes.PostService).to(PostService)
|
||||
container.bind<IUserService>(SocialProviderTypes.UserService).to(UserService)
|
||||
container.bind<IVoteService>(SocialProviderTypes.VoteService).to(VoteService)
|
||||
container.bind<IGraphService>(FirestoreClientTypes.GraphService).to(GraphService)
|
||||
container.bind<IUserTieService>(SocialProviderTypes.UserTieService).to(UserTieService)
|
||||
|
||||
|
||||
|
||||
}
|
||||
7
src/data/firestoreClient/firestoreClientTypes.ts
Normal file
7
src/data/firestoreClient/firestoreClientTypes.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* InversifyJS need to use the type as identifiers at runtime.
|
||||
* We use symbols as identifiers but you can also use classes and or string literals.
|
||||
*/
|
||||
export const FirestoreClientTypes = {
|
||||
GraphService: Symbol('GraphService')
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import { SocialError } from 'core/domain/common'
|
||||
|
||||
import { OAuthType } from 'core/domain/authorize/oauthType'
|
||||
import moment from 'moment'
|
||||
import { injectable } from 'inversify'
|
||||
/**
|
||||
* Firbase authorize service
|
||||
*
|
||||
@@ -17,6 +18,7 @@ import moment from 'moment'
|
||||
* @class AuthorizeService
|
||||
* @implements {IAuthorizeService}
|
||||
*/
|
||||
@injectable()
|
||||
export class AuthorizeService implements IAuthorizeService {
|
||||
|
||||
/**
|
||||
@@ -215,6 +217,8 @@ export class AuthorizeService implements IAuthorizeService {
|
||||
return new Promise<RegisterUserResult>((resolve,reject) => {
|
||||
db.doc(`userInfo/${userId}`).set(
|
||||
{
|
||||
id: userId,
|
||||
state: 'active',
|
||||
avatar,
|
||||
fullName,
|
||||
creationDate: moment().unix(),
|
||||
|
||||
@@ -3,8 +3,9 @@ import { firebaseRef, firebaseAuth, db } from 'data/firestoreClient'
|
||||
|
||||
import { SocialError } from 'core/domain/common'
|
||||
import { ICircleService } from 'core/services/circles'
|
||||
import { Circle, UserFollower } from 'core/domain/circles'
|
||||
import { Circle, UserTie } from 'core/domain/circles'
|
||||
import { User } from 'core/domain/users'
|
||||
import { injectable } from 'inversify'
|
||||
|
||||
/**
|
||||
* Firbase circle service
|
||||
@@ -13,12 +14,13 @@ import { User } from 'core/domain/users'
|
||||
* @class CircleService
|
||||
* @implements {ICircleService}
|
||||
*/
|
||||
@injectable()
|
||||
export class CircleService implements ICircleService {
|
||||
|
||||
public addCircle: (userId: string, circle: Circle)
|
||||
=> Promise<string> = (userId, circle) => {
|
||||
return new Promise<string>((resolve,reject) => {
|
||||
let circleRef = db.doc(`users/${userId}`).collection(`circles`).add(circle)
|
||||
let circleRef = db.doc(`users/${userId}`).collection(`circles`).add({...circle})
|
||||
circleRef.then((result) => {
|
||||
resolve(result.id as string)
|
||||
})
|
||||
@@ -27,43 +29,6 @@ export class CircleService implements ICircleService {
|
||||
|
||||
}
|
||||
|
||||
public addFollowingUser: (userId: string, circleId: string, userCircle: User, userFollower: UserFollower, userFollowingId: string)
|
||||
=> Promise<void> = (userId, circleId, userCircle, userFollower, userFollowingId) => {
|
||||
return new Promise<void>((resolve,reject) => {
|
||||
const batch = db.batch()
|
||||
const followerRef = db.doc(`users/${userId}/circles/${circleId}/users/${userFollowingId}`)
|
||||
const followingRef = db.doc(`users/${userFollowingId}/circles/-Followers/users/${userId}`)
|
||||
|
||||
batch.update(followerRef, userCircle)
|
||||
batch.update(followingRef, userFollower)
|
||||
batch.commit().then(() => {
|
||||
resolve()
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
public deleteFollowingUser: (userId: string, circleId: string, userFollowingId: string)
|
||||
=> Promise<void> = (userId, circleId, userFollowingId) => {
|
||||
return new Promise<void>((resolve,reject) => {
|
||||
|
||||
const batch = db.batch()
|
||||
const followerRef = db.doc(`users/${userId}/circles/${circleId}/users/${userFollowingId}`)
|
||||
const followingRef = db.doc(`users/${userFollowingId}/circles/-Followers/users/${userId}`)
|
||||
|
||||
batch.delete(followerRef)
|
||||
batch.delete(followingRef)
|
||||
batch.commit().then(() => {
|
||||
resolve()
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
public updateCircle: (userId: string, circleId: string, circle: Circle)
|
||||
=> Promise<void> = (userId, circleId, circle) => {
|
||||
return new Promise<void>((resolve,reject) => {
|
||||
@@ -71,7 +36,7 @@ export class CircleService implements ICircleService {
|
||||
const batch = db.batch()
|
||||
const circleRef = db.doc(`users/${userId}/circles/${circleId}`)
|
||||
|
||||
batch.update(circleRef,circle)
|
||||
batch.update(circleRef,{...circle})
|
||||
batch.commit().then(() => {
|
||||
resolve()
|
||||
})
|
||||
|
||||
153
src/data/firestoreClient/services/circles/UserTieService.ts
Normal file
153
src/data/firestoreClient/services/circles/UserTieService.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
// - Import react components
|
||||
import { datumString } from 'aws-sdk/clients/athena'
|
||||
import firebase, { firebaseRef, firebaseAuth, db } from 'data/firestoreClient'
|
||||
import moment from 'moment'
|
||||
|
||||
import { SocialError } from 'core/domain/common'
|
||||
import { Profile, UserProvider, User } from 'core/domain/users'
|
||||
import { IUserTieService } from 'core/services/circles'
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { FirestoreClientTypes } from '../../firestoreClientTypes'
|
||||
import { IGraphService } from '../graphs/IGraphService'
|
||||
import { Graph } from 'core/domain/graphs'
|
||||
import { UserTie } from 'core/domain/circles'
|
||||
|
||||
/**
|
||||
* Firbase user service
|
||||
*
|
||||
* @export
|
||||
* @class UserTieService
|
||||
* @implements {IUserTieService}
|
||||
*/
|
||||
@injectable()
|
||||
export class UserTieService implements IUserTieService {
|
||||
|
||||
constructor (
|
||||
@inject(FirestoreClientTypes.GraphService) private _graphService: IGraphService
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tie users
|
||||
*/
|
||||
public tieUseres: (userTieSenderInfo: UserTie, userTieReceiveInfo: UserTie, circleIds: string[])
|
||||
=> Promise<void> = (userTieSenderInfo, userTieReceiveInfo, circleIds) => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
|
||||
this._graphService
|
||||
.addGraph(
|
||||
new Graph(
|
||||
userTieSenderInfo.userId!,
|
||||
'TIE',
|
||||
userTieReceiveInfo.userId!,
|
||||
{...userTieSenderInfo},
|
||||
{...userTieReceiveInfo},
|
||||
{creationDate: Date.now(), circleIds}
|
||||
)
|
||||
,'users'
|
||||
).then((result) => {
|
||||
resolve()
|
||||
|
||||
})
|
||||
.catch((error: any) => reject(new SocialError(error.code, 'firestore/tieUseres :' + error.message)))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove users' tie
|
||||
*/
|
||||
public removeUsersTie: (firstUserId: string, secondUserId: string)
|
||||
=> Promise<void> = (firstUserId, secondUserId) => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
this.getUserTiesWithSeconUser(firstUserId,secondUserId).then((userTies) => {
|
||||
if (userTies.length > 0) {
|
||||
this._graphService.deleteGraphByNodeId(userTies[0].nodeId!).then(resolve)
|
||||
}
|
||||
})
|
||||
.catch((error: any) => reject(new SocialError(error.code, 'firestore/removeUsersTie :' + error.message)))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user ties
|
||||
*/
|
||||
public getUserTies: (userId: string)
|
||||
=> Promise<{[userId: string]: UserTie}> = (userId) => {
|
||||
return new Promise<{[userId: string]: UserTie}>((resolve, reject) => {
|
||||
this._graphService
|
||||
.getGraphs(
|
||||
'users',
|
||||
userId,
|
||||
'TIE')
|
||||
.then((result) => {
|
||||
|
||||
let parsedData: {[userId: string]: UserTie} = {}
|
||||
result.forEach((node) => {
|
||||
const leftUserInfo: UserTie = node.LeftMetadata
|
||||
const rightUserInfo: UserTie = node.rightMetadata
|
||||
const metadata: {creationDate: number, circleIds: string[]} = node.graphMetadata
|
||||
parsedData = {
|
||||
...parsedData,
|
||||
[rightUserInfo.userId!] : {
|
||||
...node.rightMetadata,
|
||||
circleIdList: metadata ? metadata.circleIds : []
|
||||
}
|
||||
}
|
||||
})
|
||||
resolve(parsedData)
|
||||
})
|
||||
.catch((error: any) => reject(new SocialError(error.code, 'firestore/getUserTies :' + error.message)))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the users who tied current user
|
||||
*/
|
||||
public getUserTieSender: (userId: string)
|
||||
=> Promise<{[userId: string]: UserTie}> = (userId) => {
|
||||
return new Promise<{[userId: string]: UserTie}>((resolve, reject) => {
|
||||
this._graphService
|
||||
.getGraphs(
|
||||
'users',
|
||||
null,
|
||||
'TIE',
|
||||
userId
|
||||
)
|
||||
.then((result) => {
|
||||
let parsedData: {[userId: string]: UserTie} = {}
|
||||
|
||||
result.forEach((node) => {
|
||||
const leftUserInfo: UserTie = node.LeftMetadata
|
||||
const rightUserInfo: UserTie = node.rightMetadata
|
||||
const metada: {creationDate: number, circleIds: string[]} = node.graphMetadata
|
||||
parsedData = {
|
||||
...parsedData,
|
||||
[leftUserInfo.userId!] : {
|
||||
...parsedData[leftUserInfo.userId!],
|
||||
circleIdList: []
|
||||
}
|
||||
}
|
||||
})
|
||||
resolve(parsedData)
|
||||
})
|
||||
.catch((error: any) => reject(new SocialError(error.code, 'firestore/getUserTieSender :' + error.message)))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user ties with second user identifier
|
||||
*/
|
||||
private getUserTiesWithSeconUser: (userId: string, secondUserId: string)
|
||||
=> Promise<Graph[]> = (userId, secondUserId) => {
|
||||
return new Promise<Graph[]>((resolve, reject) => {
|
||||
this._graphService
|
||||
.getGraphs(
|
||||
'users',
|
||||
userId,
|
||||
'TIE',
|
||||
secondUserId
|
||||
).then(resolve)
|
||||
.catch(reject)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import _ from 'lodash'
|
||||
import { SocialError } from 'core/domain/common'
|
||||
import { ICommentService } from 'core/services/comments'
|
||||
import { Comment } from 'core/domain/comments'
|
||||
import { injectable } from 'inversify'
|
||||
|
||||
/**
|
||||
* Firbase comment service
|
||||
@@ -13,42 +14,20 @@ import { Comment } from 'core/domain/comments'
|
||||
* @class CommentService
|
||||
* @implements {ICommentService}
|
||||
*/
|
||||
@injectable()
|
||||
export class CommentService implements ICommentService {
|
||||
|
||||
/**
|
||||
* Add comment
|
||||
*
|
||||
* @memberof CommentService
|
||||
*/
|
||||
public addComment: (comment: Comment)
|
||||
=> Promise<string> = (comment) => {
|
||||
return new Promise<string>((resolve,reject) => {
|
||||
const postRef = db.doc(`posts/${comment.postId}`)
|
||||
let commentRef = postRef.collection('comments')
|
||||
let commentRef = db.collection('comments')
|
||||
commentRef.add(comment).then((result) => {
|
||||
resolve(result.id)
|
||||
|
||||
/**
|
||||
* Add comment counter and three comments' slide preview
|
||||
*/
|
||||
db.runTransaction((transaction) => {
|
||||
return transaction.get(postRef).then((postDoc) => {
|
||||
if (postDoc.exists) {
|
||||
const commentCount = postDoc.data().commentCounter + 1
|
||||
transaction.update(postRef, { commentCounter: commentCount })
|
||||
let comments = postDoc.data()
|
||||
if (!comments) {
|
||||
comments = {}
|
||||
}
|
||||
if (commentCount < 4) {
|
||||
transaction.update(postRef, { comments: { ...comments, [result.id]: comment } })
|
||||
} else {
|
||||
let sortedObjects = comments
|
||||
// Sort posts with creation date
|
||||
sortedObjects.sort((a: any, b: any) => {
|
||||
return parseInt(b.creationDate,10) - parseInt(a.creationDate,10)
|
||||
})
|
||||
const lastCommentId = Object.keys(sortedObjects)[2]
|
||||
comments[lastCommentId] = {... comment}
|
||||
transaction.update(postRef, { comments: { ...comments} })
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code,error.message))
|
||||
@@ -56,9 +35,14 @@ export class CommentService implements ICommentService {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Get comments
|
||||
*
|
||||
* @memberof CommentService
|
||||
*/
|
||||
public getComments: (postId: string, callback: (resultComments: { [postId: string]: { [commentId: string]: Comment } }) => void)
|
||||
=> void = (postId, callback) => {
|
||||
let commentsRef = db.doc(`posts/${postId}`).collection(`comments`)
|
||||
let commentsRef = db.collection(`comments`).where('postId', '==', postId)
|
||||
commentsRef.onSnapshot((snapshot) => {
|
||||
let parsedData: {[postId: string]: {[commentId: string]: Comment}} = {[postId]: {}}
|
||||
snapshot.forEach((result) => {
|
||||
@@ -73,13 +57,18 @@ export class CommentService implements ICommentService {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Update comment
|
||||
*
|
||||
* @memberof CommentService
|
||||
*/
|
||||
public updateComment: (comment: Comment)
|
||||
=> Promise<void> = (comment) => {
|
||||
return new Promise<void>((resolve,reject) => {
|
||||
const batch = db.batch()
|
||||
const commentRef = db.doc(`posts/${comment.postId}/comments/${comment.id}`)
|
||||
const commentRef = db.collection(`comments`).doc(comment.id!)
|
||||
|
||||
batch.update(commentRef, comment)
|
||||
batch.update(commentRef, {...comment})
|
||||
batch.commit().then(() => {
|
||||
resolve()
|
||||
})
|
||||
@@ -89,45 +78,25 @@ export class CommentService implements ICommentService {
|
||||
})
|
||||
}
|
||||
|
||||
public deleteComment: (commentId: string, postId: string)
|
||||
=> Promise<void> = (commentId, postId) => {
|
||||
/**
|
||||
* Delete comment
|
||||
*
|
||||
* @memberof CommentService
|
||||
*/
|
||||
public deleteComment: (commentId: string)
|
||||
=> Promise<void> = (commentId) => {
|
||||
return new Promise<void>((resolve,reject) => {
|
||||
const batch = db.batch()
|
||||
const postRef = db.doc(`posts/${postId}`)
|
||||
const commentRef = postRef.collection(`comments`).doc(commentId)
|
||||
const commentCollectionRef = db.collection(`comments`)
|
||||
const commentRef = commentCollectionRef.doc(commentId)
|
||||
|
||||
const batch = db.batch()
|
||||
batch.delete(commentRef)
|
||||
batch.commit().then(() => {
|
||||
resolve()
|
||||
|
||||
/**
|
||||
* Delete comment counter and comments' slide preview
|
||||
*/
|
||||
db.runTransaction((transaction) => {
|
||||
return transaction.get(postRef).then((postDoc) => {
|
||||
if (postDoc.exists) {
|
||||
const commentCount = postDoc.data().commentCounter - 1
|
||||
transaction.update(postRef, { commentCounter: commentCount })
|
||||
if (commentCount > 3) {
|
||||
let comments = postDoc.data().comments
|
||||
if (!comments) {
|
||||
comments = {}
|
||||
}
|
||||
let parsedComments = {}
|
||||
Object.keys(postDoc.data().comments).map((id) => {
|
||||
if (id !== commentId) {
|
||||
_.merge(parsedComments, { [id]: { ...comments[id] } })
|
||||
}
|
||||
})
|
||||
transaction.update(postRef, { comments: { ...parsedComments}})
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code,error.message))
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code,error.message))
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { firebaseRef, firebaseAuth } from 'data/firebaseClient'
|
||||
|
||||
import { SocialError } from 'core/domain/common'
|
||||
import { ICommonService } from 'core/services/common'
|
||||
import { injectable } from 'inversify'
|
||||
|
||||
/**
|
||||
* Firbase common service
|
||||
@@ -11,6 +12,7 @@ import { ICommonService } from 'core/services/common'
|
||||
* @class CommonService
|
||||
* @implements {ICommonService}
|
||||
*/
|
||||
@injectable()
|
||||
export class CommonService implements ICommonService {
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user