[New Feature] Apply graph strategy
This commit is contained in:
@@ -1,9 +1,19 @@
|
|||||||
{
|
{
|
||||||
"hosting": {
|
"hosting": {
|
||||||
"public": "public",
|
"public": "public",
|
||||||
"rewrites": [{
|
"rewrites": [
|
||||||
"source": "**",
|
{
|
||||||
"destination": "/index.html"
|
"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",
|
"@types/react-infinite-scroller": "^1.0.4",
|
||||||
"amazon-cognito-identity-js": "^1.21.0",
|
"amazon-cognito-identity-js": "^1.21.0",
|
||||||
"aws-sdk": "^2.132.0",
|
"aws-sdk": "^2.132.0",
|
||||||
"axios": "^0.16.1",
|
"axios": "^0.16.2",
|
||||||
"babel-runtime": "^6.26.0",
|
"babel-runtime": "^6.26.0",
|
||||||
"classnames": "^2.2.5",
|
"classnames": "^2.2.5",
|
||||||
"crypto-js": "^3.1.9-1",
|
"crypto-js": "^3.1.9-1",
|
||||||
@@ -28,7 +28,8 @@
|
|||||||
"faker": "^4.1.0",
|
"faker": "^4.1.0",
|
||||||
"file-loader": "^0.11.1",
|
"file-loader": "^0.11.1",
|
||||||
"firebase": "^4.6.2",
|
"firebase": "^4.6.2",
|
||||||
"inversify": "^4.3.0",
|
"install": "^0.10.2",
|
||||||
|
"inversify": "^4.6.0",
|
||||||
"keycode": "^2.1.9",
|
"keycode": "^2.1.9",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"material-ui": "^0.19.4",
|
"material-ui": "^0.19.4",
|
||||||
@@ -36,6 +37,7 @@
|
|||||||
"morgan": "^1.8.1",
|
"morgan": "^1.8.1",
|
||||||
"node-env-file": "^0.1.8",
|
"node-env-file": "^0.1.8",
|
||||||
"node-sass": "^4.5.2",
|
"node-sass": "^4.5.2",
|
||||||
|
"npm": "^5.6.0",
|
||||||
"prop-types": "^15.6.0",
|
"prop-types": "^15.6.0",
|
||||||
"react": "^16.0.0",
|
"react": "^16.0.0",
|
||||||
"react-addons-test-utils": "^15.6.2",
|
"react-addons-test-utils": "^15.6.2",
|
||||||
@@ -43,7 +45,7 @@
|
|||||||
"react-dom": "^16.0.0",
|
"react-dom": "^16.0.0",
|
||||||
"react-event-listener": "^0.5.1",
|
"react-event-listener": "^0.5.1",
|
||||||
"react-hot-loader": "^3.1.3",
|
"react-hot-loader": "^3.1.3",
|
||||||
"react-infinite-scroller": "^1.1.1",
|
"react-infinite-scroller": "^1.1.2",
|
||||||
"react-linkify": "^0.2.1",
|
"react-linkify": "^0.2.1",
|
||||||
"react-parallax": "^1.4.4",
|
"react-parallax": "^1.4.4",
|
||||||
"react-redux": "^5.0.6",
|
"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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/bundle-v0.3.js"></script>
|
<script src="/bundle-v0.5.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -15,13 +15,16 @@ import { AuthorizeActionType } from 'constants/authorizeActionType'
|
|||||||
|
|
||||||
// - Import services
|
// - Import services
|
||||||
import { IAuthorizeService } from 'core/services/authorize'
|
import { IAuthorizeService } from 'core/services/authorize'
|
||||||
import { IServiceProvider, ServiceProvide } from 'core/factories'
|
|
||||||
|
|
||||||
// - Import actions
|
// - Import actions
|
||||||
import * as globalActions from 'actions/globalActions'
|
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 _____________ */
|
/* _____________ CRUD DB _____________ */
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// - Import domain
|
// - Import domain
|
||||||
import { User } from 'core/domain/users'
|
import { User, Profile } from 'core/domain/users'
|
||||||
import { Circle, UserFollower } from 'core/domain/circles'
|
import { Circle, UserTie } from 'core/domain/circles'
|
||||||
import { SocialError } from 'core/domain/common'
|
import { SocialError } from 'core/domain/common'
|
||||||
|
|
||||||
// - Import utility components
|
// - Import utility components
|
||||||
@@ -15,11 +15,17 @@ import * as postActions from 'actions/postActions'
|
|||||||
import * as userActions from 'actions/userActions'
|
import * as userActions from 'actions/userActions'
|
||||||
import * as notifyActions from 'actions/notifyActions'
|
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 { 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 _____________ */
|
/* _____________ CRUD DB _____________ */
|
||||||
|
|
||||||
@@ -33,10 +39,9 @@ export let dbAddCircle = (circleName: string) => {
|
|||||||
let uid: string = getState().authorize.uid
|
let uid: string = getState().authorize.uid
|
||||||
let circle: Circle = {
|
let circle: Circle = {
|
||||||
creationDate: moment().unix(),
|
creationDate: moment().unix(),
|
||||||
name: circleName,
|
name: circleName
|
||||||
users: {}
|
|
||||||
}
|
}
|
||||||
return circleService.addCircle(uid,circle).then((circleKey: string) => {
|
return circleService.addCircle(uid, circle).then((circleKey: string) => {
|
||||||
circle.id = circleKey
|
circle.id = circleKey
|
||||||
circle.ownerId = uid
|
circle.ownerId = uid
|
||||||
dispatch(addCircle(circle))
|
dispatch(addCircle(circle))
|
||||||
@@ -47,31 +52,29 @@ export let dbAddCircle = (circleName: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a user in a circle
|
* Update user in circle/circles
|
||||||
* @param {string} cid is circle identifier
|
|
||||||
* @param {User} userFollowing is the user for following
|
|
||||||
*/
|
*/
|
||||||
export let dbAddFollowingUser = (cid: string, userFollowing: UserFollower) => {
|
export let dbUpdateUserInCircles = (circleIdList: string[], userFollowing: UserTie) => {
|
||||||
return (dispatch: any, getState: Function) => {
|
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
|
return userTieService.tieUseres(
|
||||||
let user: User = getState().user.info[uid]
|
{ userId: user.userId!, fullName: user.fullName, avatar: user.avatar, approved: false },
|
||||||
|
{ userId: userFollowing.userId!, fullName: userFollowing.fullName, avatar: userFollowing.avatar, approved: false },
|
||||||
let userCircle: User = {
|
circleIdList
|
||||||
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)
|
|
||||||
.then(() => {
|
.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(
|
dispatch(notifyActions.dbAddNotification(
|
||||||
{
|
{
|
||||||
@@ -89,18 +92,16 @@ export let dbAddFollowingUser = (cid: string, userFollowing: UserFollower) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a user from a circle
|
* Delete following user
|
||||||
* @param {string} cid is circle identifier
|
|
||||||
* @param {string} userFollowingId following user identifier
|
|
||||||
*/
|
*/
|
||||||
export let dbDeleteFollowingUser = (cid: string, userFollowingId: string) => {
|
export let dbDeleteFollowingUser = (userFollowingId: string) => {
|
||||||
return (dispatch: any, getState: Function) => {
|
return (dispatch: any, getState: Function) => {
|
||||||
|
|
||||||
let uid: string = getState().authorize.uid
|
let uid: string = getState().authorize.uid
|
||||||
|
|
||||||
return circleService.deleteFollowingUser(uid,cid,userFollowingId)
|
return userTieService.removeUsersTie(uid, userFollowingId)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
dispatch(deleteFollowingUser(uid, cid, userFollowingId))
|
dispatch(deleteFollowingUser(userFollowingId))
|
||||||
}, (error: SocialError) => {
|
}, (error: SocialError) => {
|
||||||
dispatch(globalActions.showErrorMessage(error.message))
|
dispatch(globalActions.showErrorMessage(error.message))
|
||||||
})
|
})
|
||||||
@@ -109,7 +110,6 @@ export let dbDeleteFollowingUser = (cid: string, userFollowingId: string) => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a circle from database
|
* Update a circle from database
|
||||||
* @param {Circle} newCircle
|
|
||||||
*/
|
*/
|
||||||
export const dbUpdateCircle = (newCircle: Circle) => {
|
export const dbUpdateCircle = (newCircle: Circle) => {
|
||||||
return (dispatch: any, getState: Function) => {
|
return (dispatch: any, getState: Function) => {
|
||||||
@@ -118,14 +118,13 @@ export const dbUpdateCircle = (newCircle: Circle) => {
|
|||||||
let uid: string = getState().authorize.uid
|
let uid: string = getState().authorize.uid
|
||||||
|
|
||||||
// Write the new data simultaneously in the list
|
// 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 = {
|
let updatedCircle: Circle = {
|
||||||
name: newCircle.name || circle.name,
|
name: newCircle.name || circle.name
|
||||||
users: newCircle.users ? newCircle.users : (circle.users || [])
|
|
||||||
}
|
}
|
||||||
return circleService.updateCircle(uid,newCircle.id!,circle)
|
return circleService.updateCircle(uid, newCircle.id!, circle)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
dispatch(updateCircle(uid,{ id: newCircle.id, ...updatedCircle }))
|
dispatch(updateCircle({ id: newCircle.id, ...updatedCircle }))
|
||||||
}, (error: SocialError) => {
|
}, (error: SocialError) => {
|
||||||
dispatch(globalActions.showErrorMessage(error.message))
|
dispatch(globalActions.showErrorMessage(error.message))
|
||||||
})
|
})
|
||||||
@@ -135,17 +134,16 @@ export const dbUpdateCircle = (newCircle: Circle) => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a circle from database
|
* 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) => {
|
return (dispatch: any, getState: Function) => {
|
||||||
|
|
||||||
// Get current user id
|
// Get current user id
|
||||||
let uid: string = getState().authorize.uid
|
let uid: string = getState().authorize.uid
|
||||||
|
|
||||||
return circleService.deleteCircle(uid,id)
|
return circleService.deleteCircle(uid, circleId)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
dispatch(deleteCircle(uid, id))
|
dispatch(deleteCircle(circleId))
|
||||||
}, (error: SocialError) => {
|
}, (error: SocialError) => {
|
||||||
dispatch(globalActions.showErrorMessage(error.message))
|
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 = () => {
|
export const dbGetCircles = () => {
|
||||||
return (dispatch: any, getState: Function) => {
|
return (dispatch: any, getState: Function) => {
|
||||||
@@ -163,16 +161,7 @@ export const dbGetCircles = () => {
|
|||||||
|
|
||||||
return circleService.getCircles(uid)
|
return circleService.getCircles(uid)
|
||||||
.then((circles: { [circleId: string]: Circle }) => {
|
.then((circles: { [circleId: string]: Circle }) => {
|
||||||
Object.keys(circles).forEach((circleId) => {
|
dispatch(addCircles(circles))
|
||||||
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))
|
|
||||||
})
|
})
|
||||||
.catch((error: SocialError) => {
|
.catch((error: SocialError) => {
|
||||||
dispatch(globalActions.showErrorMessage(error.message))
|
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
|
* Get all user circles from data base by user id
|
||||||
* @param uid user identifier
|
* @param uid user identifier
|
||||||
@@ -191,12 +220,12 @@ export const dbGetCirclesByUserId = (uid: string) => {
|
|||||||
|
|
||||||
if (uid) {
|
if (uid) {
|
||||||
return circleService.getCircles(uid)
|
return circleService.getCircles(uid)
|
||||||
.then((circles: { [circleId: string]: Circle }) => {
|
.then((circles: { [circleId: string]: Circle }) => {
|
||||||
dispatch(addCircles(uid, circles))
|
dispatch(addCircles(circles))
|
||||||
})
|
})
|
||||||
.catch((error: SocialError) => {
|
.catch((error: SocialError) => {
|
||||||
dispatch(globalActions.showErrorMessage(error.message))
|
dispatch(globalActions.showErrorMessage(error.message))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -204,9 +233,7 @@ export const dbGetCirclesByUserId = (uid: string) => {
|
|||||||
/* _____________ CRUD State _____________ */
|
/* _____________ CRUD State _____________ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a normal circle
|
* Add a circle
|
||||||
* @param {string} uid is user identifier
|
|
||||||
* @param {Circle} circle
|
|
||||||
*/
|
*/
|
||||||
export const addCircle = (circle: Circle) => {
|
export const addCircle = (circle: Circle) => {
|
||||||
return {
|
return {
|
||||||
@@ -217,37 +244,31 @@ export const addCircle = (circle: Circle) => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a 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 {
|
return {
|
||||||
type: CircleActionType.UPDATE_CIRCLE,
|
type: CircleActionType.UPDATE_CIRCLE,
|
||||||
payload: { uid, circle }
|
payload: { circle }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a 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 {
|
return {
|
||||||
type: CircleActionType.DELETE_CIRCLE,
|
type: CircleActionType.DELETE_CIRCLE,
|
||||||
payload: { uid, id }
|
payload: { circleId }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a list of circle
|
* 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 {
|
return {
|
||||||
type: CircleActionType.ADD_LIST_CIRCLE,
|
type: CircleActionType.ADD_LIST_CIRCLE,
|
||||||
payload: { uid, circles }
|
payload: { circleList }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,55 +283,126 @@ export const clearAllCircles = () => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Open circle settings
|
* Open circle settings
|
||||||
* @param uid user idenifier
|
|
||||||
* @param id circle identifier
|
|
||||||
*/
|
*/
|
||||||
export const openCircleSettings = (uid: string, id: string) => {
|
export const openCircleSettings = (circleId: string) => {
|
||||||
return {
|
return {
|
||||||
type: CircleActionType.OPEN_CIRCLE_SETTINGS,
|
type: CircleActionType.OPEN_CIRCLE_SETTINGS,
|
||||||
payload: { uid, id }
|
payload: { circleId }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close open circle settings
|
* 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 {
|
return {
|
||||||
type: CircleActionType.CLOSE_CIRCLE_SETTINGS,
|
type: CircleActionType.CLOSE_CIRCLE_SETTINGS,
|
||||||
payload: { uid, id }
|
payload: { circleId }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add following user in a circle
|
* Add following user
|
||||||
* @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
|
|
||||||
*/
|
*/
|
||||||
export const addFollowingUser = (uid: string, cid: string, followingId: string, userCircle: User) => {
|
export const addFollowingUser = (userTie: UserTie) => {
|
||||||
return {
|
return {
|
||||||
type: CircleActionType.ADD_FOLLOWING_USER,
|
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
|
* Hide the box to select 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
|
|
||||||
*/
|
*/
|
||||||
export const deleteFollowingUser = (uid: string, cid: string, followingId: string) => {
|
export const hideSelectCircleBox = (userId: string) => {
|
||||||
return {
|
return {
|
||||||
type: CircleActionType.DELETE_FOLLOWING_USER,
|
type: CircleActionType.HIDE_SELECT_CIRCLE_BOX,
|
||||||
payload: { uid, cid, followingId }
|
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 react components
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
import _ from 'lodash'
|
||||||
|
|
||||||
// - Import domain
|
// - Import domain
|
||||||
import { Comment } from 'core/domain/comments'
|
import { Comment } from 'core/domain/comments'
|
||||||
@@ -14,11 +15,14 @@ import * as globalActions from 'actions/globalActions'
|
|||||||
import * as notifyActions from 'actions/notifyActions'
|
import * as notifyActions from 'actions/notifyActions'
|
||||||
import * as postActions from 'actions/postActions'
|
import * as postActions from 'actions/postActions'
|
||||||
|
|
||||||
import { IServiceProvider, ServiceProvide } from 'core/factories'
|
|
||||||
import { ICommentService } from 'core/services/comments'
|
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 _____________ */
|
/* _____________ CRUD DB _____________ */
|
||||||
|
|
||||||
@@ -28,11 +32,12 @@ const commentService: ICommentService = serviceProvider.createCommentService()
|
|||||||
* @param {object} newComment user comment
|
* @param {object} newComment user comment
|
||||||
* @param {function} callBack will be fired when server responsed
|
* @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) => {
|
return (dispatch: any, getState: Function) => {
|
||||||
|
|
||||||
dispatch(globalActions.showTopLoading())
|
dispatch(globalActions.showTopLoading())
|
||||||
|
|
||||||
|
const state = getState()
|
||||||
let uid: string = getState().authorize.uid
|
let uid: string = getState().authorize.uid
|
||||||
|
|
||||||
let comment: Comment = {
|
let comment: Comment = {
|
||||||
@@ -74,8 +79,10 @@ export const dbAddComment = (ownerPostUserId: string | null,newComment: Comment,
|
|||||||
*/
|
*/
|
||||||
export const dbGetComments = (ownerUserId: string, postId: string) => {
|
export const dbGetComments = (ownerUserId: string, postId: string) => {
|
||||||
return (dispatch: any, getState: Function) => {
|
return (dispatch: any, getState: Function) => {
|
||||||
|
const state = getState()
|
||||||
let uid: string = getState().authorize.uid
|
let uid: string = getState().authorize.uid
|
||||||
if (uid) {
|
if (uid) {
|
||||||
|
|
||||||
return commentService.getComments(postId, (comments: {[postId: string]: {[commentId: string]: Comment}}) => {
|
return commentService.getComments(postId, (comments: {[postId: string]: {[commentId: string]: Comment}}) => {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,24 +96,21 @@ export const dbGetComments = (ownerUserId: string, postId: string) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (comments && Object.keys(comments).length > 0) {
|
const desiredComments = comments[postId]
|
||||||
commentsCount = Object.keys(comments).length
|
if (desiredComments && Object.keys(desiredComments).length > 0) {
|
||||||
let sortedObjects = comments as any
|
commentsCount = Object.keys(desiredComments).length
|
||||||
|
let sortedObjects = desiredComments as any
|
||||||
// Sort posts with creation date
|
// 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} postId is the identifier of the post which comment belong to
|
||||||
* @param {string} text is the text of comment
|
* @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) => {
|
return (dispatch: any, getState: Function) => {
|
||||||
|
delete comment.editorStatus
|
||||||
dispatch(globalActions.showTopLoading())
|
dispatch(globalActions.showTopLoading())
|
||||||
|
|
||||||
// Get current user id
|
// Get current user id
|
||||||
let uid: string = getState().authorize.uid
|
let uid: string = getState().authorize.uid
|
||||||
|
|
||||||
// Write the new data simultaneously in the list
|
return commentService.updateComment(comment)
|
||||||
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)
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
dispatch(updateComment( id, postId, text))
|
dispatch(updateComment( comment))
|
||||||
dispatch(globalActions.hideTopLoading())
|
dispatch(globalActions.hideTopLoading())
|
||||||
|
|
||||||
}, (error: SocialError) => {
|
}, (error: SocialError) => {
|
||||||
@@ -168,7 +160,7 @@ export const dbDeleteComment = (id?: string | null, postId?: string) => {
|
|||||||
// Get current user id
|
// Get current user id
|
||||||
let uid: string = getState().authorize.uid
|
let uid: string = getState().authorize.uid
|
||||||
|
|
||||||
return commentService.deleteComment(id!,postId!)
|
return commentService.deleteComment(id!)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
dispatch(deleteComment(id!, postId!))
|
dispatch(deleteComment(id!, postId!))
|
||||||
dispatch(globalActions.hideTopLoading())
|
dispatch(globalActions.hideTopLoading())
|
||||||
@@ -202,11 +194,11 @@ export const addComment = (comment: Comment) => {
|
|||||||
* @param postId post identefier which comment belong to
|
* @param postId post identefier which comment belong to
|
||||||
* @param text the new text for comment
|
* @param text the new text for comment
|
||||||
*/
|
*/
|
||||||
export const updateComment = ( id: string, postId: string, text: string) => {
|
export const updateComment = ( comment: Comment) => {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: CommentActionType.UPDATE_COMMENT,
|
type: CommentActionType.UPDATE_COMMENT,
|
||||||
payload: {id, postId, text}
|
payload: { comment }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,23 @@ export const hideMessage = () => {
|
|||||||
* @param {string} message
|
* @param {string} message
|
||||||
*/
|
*/
|
||||||
export const showErrorMessage = (message: string) => {
|
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 {
|
return {
|
||||||
type: GlobalActionType.SHOW_ERROR_MESSAGE_GLOBAL,
|
type: GlobalActionType.SHOW_ERROR_MESSAGE_GLOBAL,
|
||||||
payload: message
|
payload: message
|
||||||
|
|||||||
@@ -15,13 +15,16 @@ import * as globalActions from 'actions/globalActions'
|
|||||||
// - Import app API
|
// - Import app API
|
||||||
import FileAPI from 'api/FileAPI'
|
import FileAPI from 'api/FileAPI'
|
||||||
|
|
||||||
import { IServiceProvider, ServiceProvide } from 'core/factories'
|
|
||||||
import { IImageGalleryService } from 'core/services/imageGallery'
|
import { IImageGalleryService } from 'core/services/imageGallery'
|
||||||
import { FileResult } from 'models/files/fileResult'
|
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()
|
* Get service providers
|
||||||
const storageService: IStorageService = serviceProvider.createStorageService()
|
*/
|
||||||
|
const imageGalleryService: IImageGalleryService = provider.get<IImageGalleryService>(SocialProviderTypes.ImageGalleryService)
|
||||||
|
const storageService: IStorageService = provider.get<IStorageService>(SocialProviderTypes.StorageService)
|
||||||
|
|
||||||
/* _____________ UI Actions _____________ */
|
/* _____________ UI Actions _____________ */
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,14 @@ import { NotificationActionType } from 'constants/notificationActionType'
|
|||||||
import * as globalActions from 'actions/globalActions'
|
import * as globalActions from 'actions/globalActions'
|
||||||
import * as userActions from 'actions/userActions'
|
import * as userActions from 'actions/userActions'
|
||||||
|
|
||||||
import { IServiceProvider, ServiceProvide } from 'core/factories'
|
|
||||||
import { INotificationService } from 'core/services/notifications'
|
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 _____________ */
|
/* _____________ CRUD DB _____________ */
|
||||||
|
|
||||||
|
|||||||
@@ -15,11 +15,14 @@ import { PostActionType } from 'constants/postActionType'
|
|||||||
// - Import actions
|
// - Import actions
|
||||||
import * as globalActions from 'actions/globalActions'
|
import * as globalActions from 'actions/globalActions'
|
||||||
|
|
||||||
import { IServiceProvider, ServiceProvide } from 'core/factories'
|
|
||||||
import { IPostService } from 'core/services/posts'
|
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 _____________ */
|
/* _____________ CRUD DB _____________ */
|
||||||
|
|
||||||
@@ -127,7 +130,7 @@ export const dbUpdatePost = (updatedPost: Post, callBack: Function) => {
|
|||||||
|
|
||||||
return postService.updatePost(updatedPost).then(() => {
|
return postService.updatePost(updatedPost).then(() => {
|
||||||
|
|
||||||
dispatch(updatePost(uid, { ...updatedPost }))
|
dispatch(updatePost(updatedPost))
|
||||||
callBack()
|
callBack()
|
||||||
dispatch(globalActions.hideTopLoading())
|
dispatch(globalActions.hideTopLoading())
|
||||||
|
|
||||||
@@ -169,13 +172,88 @@ export const dbDeletePost = (id: string) => {
|
|||||||
/**
|
/**
|
||||||
* Get all user posts from data base
|
* Get all user posts from data base
|
||||||
*/
|
*/
|
||||||
export const dbGetPosts = () => {
|
export const dbGetPosts = (page: number = 0, limit: number = 10) => {
|
||||||
return (dispatch: any, getState: Function) => {
|
return (dispatch: any, getState: Function) => {
|
||||||
let uid: string = getState().authorize.uid
|
const state = getState()
|
||||||
if (uid) {
|
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 }) => {
|
let uid: string = state.authorize.uid
|
||||||
dispatch(addPosts(uid, posts))
|
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) => {
|
.catch((error: SocialError) => {
|
||||||
dispatch(globalActions.showErrorMessage(error.message))
|
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 _____________ */
|
/* _____________ CRUD State _____________ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -240,10 +302,10 @@ export const addPost = (uid: string, post: Post) => {
|
|||||||
* @param {string} uid is user identifier
|
* @param {string} uid is user identifier
|
||||||
* @param {Post} post
|
* @param {Post} post
|
||||||
*/
|
*/
|
||||||
export const updatePost = (uid: string, post: Post) => {
|
export const updatePost = (post: Post) => {
|
||||||
return {
|
return {
|
||||||
type: PostActionType.UPDATE_POST,
|
type: PostActionType.UPDATE_POST,
|
||||||
payload: { uid, post }
|
payload: { post }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,10 +326,10 @@ export const deletePost = (uid: string, id: string) => {
|
|||||||
* @param {string} uid
|
* @param {string} uid
|
||||||
* @param {[object]} posts
|
* @param {[object]} posts
|
||||||
*/
|
*/
|
||||||
export const addPosts = (uid: string, posts: { [postId: string]: Post }) => {
|
export const addPosts = (userPosts: { [userId: string]: {[postId: string]: Post} }) => {
|
||||||
return {
|
return {
|
||||||
type: PostActionType.ADD_LIST_POST,
|
type: PostActionType.ADD_LIST_POST,
|
||||||
payload: { uid, posts }
|
payload: { userPosts }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,7 +344,6 @@ export const clearAllData = () => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a post with image
|
* Add a post with image
|
||||||
* @param {object} post
|
|
||||||
*/
|
*/
|
||||||
export const addImagePost = (uid: string, post: any) => {
|
export const addImagePost = (uid: string, post: any) => {
|
||||||
return {
|
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 react components
|
||||||
|
import { provider } from '../socialEngine'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
// - Import domain
|
// - Import domain
|
||||||
import { Profile } from 'core/domain/users'
|
import { Profile } from 'core/domain/users'
|
||||||
@@ -11,11 +12,13 @@ import { UserActionType } from 'constants/userActionType'
|
|||||||
import * as globalActions from 'actions/globalActions'
|
import * as globalActions from 'actions/globalActions'
|
||||||
import * as userActions from 'actions/userActions'
|
import * as userActions from 'actions/userActions'
|
||||||
|
|
||||||
import { IServiceProvider, ServiceProvide } from 'core/factories'
|
|
||||||
import { IUserService } from 'core/services/users'
|
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 _____________ */
|
/* _____________ CRUD DB _____________ */
|
||||||
|
|
||||||
@@ -93,7 +96,7 @@ export const dbUpdateUserInfo = (newProfile: Profile) => {
|
|||||||
let uid: string = getState().authorize.uid
|
let uid: string = getState().authorize.uid
|
||||||
|
|
||||||
let profile: Profile = getState().user.info[uid]
|
let profile: Profile = getState().user.info[uid]
|
||||||
let updatedProfie: Profile = {
|
let updatedProfile: Profile = {
|
||||||
avatar: newProfile.avatar || profile.avatar || '',
|
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',
|
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 || '',
|
email: newProfile.email || profile.email || '',
|
||||||
@@ -101,10 +104,9 @@ export const dbUpdateUserInfo = (newProfile: Profile) => {
|
|||||||
tagLine: newProfile.tagLine || profile.tagLine || '',
|
tagLine: newProfile.tagLine || profile.tagLine || '',
|
||||||
creationDate: newProfile.creationDate
|
creationDate: newProfile.creationDate
|
||||||
}
|
}
|
||||||
|
return userService.updateUserProfile(uid,updatedProfile).then(() => {
|
||||||
|
|
||||||
return userService.updateUserProfile(uid,updatedProfie).then(() => {
|
dispatch(updateUserInfo(uid, updatedProfile))
|
||||||
|
|
||||||
dispatch(updateUserInfo(uid, updatedProfie))
|
|
||||||
dispatch(closeEditProfile())
|
dispatch(closeEditProfile())
|
||||||
})
|
})
|
||||||
.catch((error: SocialError) => dispatch(globalActions.showErrorMessage(error.message)))
|
.catch((error: SocialError) => dispatch(globalActions.showErrorMessage(error.message)))
|
||||||
@@ -114,17 +116,40 @@ export const dbUpdateUserInfo = (newProfile: Profile) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// - Get people info from database
|
// - Get people info from database
|
||||||
export const dbGetPeopleInfo = (page?: number) => {
|
export const dbGetPeopleInfo = (page: number, limit: number) => {
|
||||||
return (dispatch: any, getState: Function) => {
|
return (dispatch: any, getState: Function) => {
|
||||||
const {authorize, user} = getState()
|
const state = getState()
|
||||||
let uid: string = authorize.uid
|
const {people} = state.user
|
||||||
if (uid) {
|
const lastPageRequest = people.lastPageRequest
|
||||||
const lastKey = ''
|
const lastUserId = people.lastUserId
|
||||||
return userService.getUsersProfile(uid, lastKey)
|
const hasMoreData = people.hasMoreData
|
||||||
.then((usersProfile: {[userId: string]: Profile}) => {
|
|
||||||
dispatch(addPeopleInfo(usersProfile))
|
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 = () => {
|
export const clearAllData = () => {
|
||||||
return {
|
return {
|
||||||
type: UserActionType.CLEAR_ALL_DATA_USER
|
type: UserActionType.CLEAR_ALL_DATA_USER
|
||||||
@@ -202,4 +216,46 @@ export const closeEditProfile = () => {
|
|||||||
type: UserActionType.CLOSE_EDIT_PROFILE
|
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 notifyActions from 'actions/notifyActions'
|
||||||
import * as postActions from 'actions/postActions'
|
import * as postActions from 'actions/postActions'
|
||||||
|
|
||||||
import { IServiceProvider, ServiceProvide } from 'core/factories'
|
|
||||||
import { IVoteService } from 'core/services/votes'
|
import { IVoteService } from 'core/services/votes'
|
||||||
import { Post } from 'core/domain/posts'
|
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 _____________ */
|
/* _____________ CRUD DB _____________ */
|
||||||
|
|
||||||
@@ -40,7 +43,8 @@ export const dbAddVote = (postId: string,ownerPostUserId: string) => {
|
|||||||
const post: Post = state.post.userPosts[ownerPostUserId][postId]
|
const post: Post = state.post.userPosts[ownerPostUserId][postId]
|
||||||
|
|
||||||
post.score! += 1
|
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) => {
|
return voteService.addVote(vote).then((voteKey: string) => {
|
||||||
if (uid !== ownerPostUserId) {
|
if (uid !== ownerPostUserId) {
|
||||||
@@ -56,7 +60,8 @@ export const dbAddVote = (postId: string,ownerPostUserId: string) => {
|
|||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
post.score! -= 1
|
post.score! -= 1
|
||||||
dispatch(postActions.updatePost(ownerPostUserId,post))
|
post.votes = { ...post.votes!, [uid]: false}
|
||||||
|
dispatch(postActions.updatePost(post))
|
||||||
dispatch(globalActions.showErrorMessage(error.message))
|
dispatch(globalActions.showErrorMessage(error.message))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -99,17 +104,15 @@ export const dbDeleteVote = (postId: string, ownerPostUserId: string) => {
|
|||||||
const state = getState()
|
const state = getState()
|
||||||
// Get current user id
|
// Get current user id
|
||||||
let uid: string = state.authorize.uid
|
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]
|
const post: Post = state.post.userPosts[ownerPostUserId][postId]
|
||||||
post.score! -= 1
|
post.score! -= 1
|
||||||
dispatch(postActions.updatePost(ownerPostUserId,post))
|
post.votes = { ...post.votes!, [uid]: false}
|
||||||
return voteService.deleteVote(vote).then(x => x)
|
dispatch(postActions.updatePost(post))
|
||||||
|
return voteService.deleteVote(uid, postId).then(x => x)
|
||||||
.catch((error: any) => {
|
.catch((error: any) => {
|
||||||
post.score! += 1
|
post.score! += 1
|
||||||
dispatch(postActions.updatePost(ownerPostUserId,post))
|
post.votes = { ...post.votes!, [uid]: true}
|
||||||
|
dispatch(postActions.updatePost(post))
|
||||||
dispatch(globalActions.showErrorMessage(error.message))
|
dispatch(globalActions.showErrorMessage(error.message))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -129,8 +132,8 @@ export const addVote = (vote: Vote) => {
|
|||||||
* @param {string} id vote identifier
|
* @param {string} id vote identifier
|
||||||
* @param {string} postId post identifier which vote on
|
* @param {string} postId post identifier which vote on
|
||||||
*/
|
*/
|
||||||
export const deleteVote = (id: string, postId: string) => {
|
export const deleteVote = (userId: string, postId: string) => {
|
||||||
return { type: VoteActionType.DELETE_VOTE, payload: {id, postId} }
|
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
|
* 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
|
* @param {object} circles
|
||||||
*/
|
*/
|
||||||
export const getFollowingUsers = (circles: {[circleId: string]: Circle}) => {
|
export const getFollowingUsers = (circles: {[circleId: string]: Circle}) => {
|
||||||
let followingUsers: {[userId: string]: UserFollower} = {}
|
let followingUsers: {[userId: string]: UserTie} = {}
|
||||||
Object.keys(circles).forEach((cid) => {
|
Object.keys(circles).forEach((cid) => {
|
||||||
if (cid.trim() !== '-Followers' && circles[cid].users) {
|
if (cid.trim() !== '-Followers' && circles[cid].users) {
|
||||||
Object.keys(circles[cid].users).forEach((userId) => {
|
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
|
// - Import actions
|
||||||
|
|
||||||
const isValidEmail = (email: string) => {
|
const isValidEmail = (email: string) => {
|
||||||
@@ -5,6 +7,10 @@ const isValidEmail = (email: string) => {
|
|||||||
return re.test(email)
|
return re.test(email)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const createServerRequestId = (requestType: ServerRequestType, uniqueId: string) => {
|
||||||
|
return `${requestType}:${uniqueId}`
|
||||||
|
}
|
||||||
|
|
||||||
function queryString (name: string, url: string = window.location.href) {
|
function queryString (name: string, url: string = window.location.href) {
|
||||||
name = name.replace(/[[]]/g, '\\$&')
|
name = name.replace(/[[]]/g, '\\$&')
|
||||||
|
|
||||||
@@ -23,5 +29,6 @@ function queryString (name: string, url: string = window.location.href) {
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
isValidEmail,
|
isValidEmail,
|
||||||
queryString
|
queryString,
|
||||||
|
createServerRequestId
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -244,8 +244,8 @@ const mapDispatchToProps = (dispatch: any, ownProps: ICircleComponentProps) => {
|
|||||||
return {
|
return {
|
||||||
deleteCircle: (id: string) => dispatch(circleActions.dbDeleteCircle(id)),
|
deleteCircle: (id: string) => dispatch(circleActions.dbDeleteCircle(id)),
|
||||||
updateCircle: (circle: Circle) => dispatch(circleActions.dbUpdateCircle(circle)),
|
updateCircle: (circle: Circle) => dispatch(circleActions.dbUpdateCircle(circle)),
|
||||||
closeCircleSettings: () => dispatch(circleActions.closeCircleSettings(uid, ownProps.id)),
|
closeCircleSettings: () => dispatch(circleActions.closeCircleSettings(ownProps.id)),
|
||||||
openCircleSettings: () => dispatch(circleActions.openCircleSettings(uid, ownProps.id)),
|
openCircleSettings: () => dispatch(circleActions.openCircleSettings(ownProps.id)),
|
||||||
goTo: (url: string) => dispatch(push(url))
|
goTo: (url: string) => dispatch(push(url))
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -258,9 +258,12 @@ const mapDispatchToProps = (dispatch: any, ownProps: ICircleComponentProps) => {
|
|||||||
* @return {object} props of component
|
* @return {object} props of component
|
||||||
*/
|
*/
|
||||||
const mapStateToProps = (state: any, ownProps: ICircleComponentProps) => {
|
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 {
|
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
|
userInfo: state.user.info
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import PropTypes from 'prop-types'
|
|||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import Linkify from 'react-linkify'
|
import Linkify from 'react-linkify'
|
||||||
|
|
||||||
|
import { Comment } from 'core/domain/comments'
|
||||||
|
|
||||||
// - Import material UI libraries
|
// - Import material UI libraries
|
||||||
import { List, ListItem } from 'material-ui/List'
|
import { List, ListItem } from 'material-ui/List'
|
||||||
import Divider from 'material-ui/Divider'
|
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
|
* @param {event} evt is an event passed by clicking on post button
|
||||||
*/
|
*/
|
||||||
handleUpdateComment = (evt: any) => {
|
handleUpdateComment = (evt: any) => {
|
||||||
|
const {comment} = this.props
|
||||||
this.props.update(this.props.comment.id, this.props.comment.postId, this.state.text)
|
comment.editorStatus = undefined
|
||||||
|
comment.text = this.state.text
|
||||||
|
this.props.update(comment)
|
||||||
this.setState({
|
this.setState({
|
||||||
initialText: this.state.text
|
initialText: this.state.text
|
||||||
})
|
})
|
||||||
@@ -302,13 +306,18 @@ export class CommentComponent extends Component<ICommentComponentProps,ICommentC
|
|||||||
* @param {object} ownProps is the props belong to component
|
* @param {object} ownProps is the props belong to component
|
||||||
* @return {object} props of component
|
* @return {object} props of component
|
||||||
*/
|
*/
|
||||||
const mapDispatchToProps = (dispatch: any, ownProps: any) => {
|
const mapDispatchToProps = (dispatch: any, ownProps: ICommentComponentProps) => {
|
||||||
return {
|
return {
|
||||||
delete: (id: string| null, postId: string) => dispatch(commentActions.dbDeleteComment(id, postId)),
|
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 })),
|
openEditor: () => dispatch(commentActions.openCommentEditor({ id: ownProps.comment.id, postId: ownProps.comment.postId })),
|
||||||
closeEditor: () => dispatch(commentActions.closeCommentEditor({ 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
|
* @memberof ICommentComponentProps
|
||||||
*/
|
*/
|
||||||
update: (id?: string | null, postId?: string, comment?: string | null) => any
|
update: (comment: Comment) => any
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete comment
|
* Delete comment
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// - Import react components
|
// - Import react components
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
import _ from 'lodash'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import Paper from 'material-ui/Paper'
|
import Paper from 'material-ui/Paper'
|
||||||
import FlatButton from 'material-ui/FlatButton'
|
import FlatButton from 'material-ui/FlatButton'
|
||||||
@@ -101,7 +102,7 @@ export class CommentGroupComponent extends Component<ICommentGroupComponentProps
|
|||||||
clearCommentWrite = () => {
|
clearCommentWrite = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
commentText: '',
|
commentText: '',
|
||||||
postDisable: false
|
postDisable: true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +110,10 @@ export class CommentGroupComponent extends Component<ICommentGroupComponentProps
|
|||||||
* Post comment
|
* Post comment
|
||||||
*/
|
*/
|
||||||
handlePostComment = () => {
|
handlePostComment = () => {
|
||||||
|
|
||||||
this.props.send!(this.state.commentText, this.props.postId, this.clearCommentWrite)
|
this.props.send!(this.state.commentText, this.props.postId, this.clearCommentWrite)
|
||||||
|
|
||||||
|
this.clearCommentWrite()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -140,9 +144,10 @@ export class CommentGroupComponent extends Component<ICommentGroupComponentProps
|
|||||||
commentList = () => {
|
commentList = () => {
|
||||||
let comments = this.props.commentSlides
|
let comments = this.props.commentSlides
|
||||||
if (comments) {
|
if (comments) {
|
||||||
|
comments = _.fromPairs(_.toPairs(comments)
|
||||||
|
.sort((a: any, b: any) => parseInt(b[1].creationDate,10) - parseInt(a[1].creationDate,10)))
|
||||||
let parsedComments: Comment[] = []
|
let parsedComments: Comment[] = []
|
||||||
Object.keys(comments).slice(0, 3).forEach((commentId) => {
|
Object.keys(comments).forEach((commentId) => {
|
||||||
parsedComments.push({
|
parsedComments.push({
|
||||||
id: commentId,
|
id: commentId,
|
||||||
...comments![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} />
|
<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>
|
</Paper>
|
||||||
</div>)
|
</div>)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return Elements
|
* Return Elements
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -227,7 +227,8 @@ export class EditProfileComponent extends Component<IEditProfileComponentProps,I
|
|||||||
fullName: fullNameInput,
|
fullName: fullNameInput,
|
||||||
tagLine: tagLineInput,
|
tagLine: tagLineInput,
|
||||||
avatar: avatar,
|
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 app components
|
||||||
import UserBoxList from 'components/userBoxList'
|
import UserBoxList from 'components/userBoxList'
|
||||||
|
import LoadMoreProgressComponent from 'layouts/loadMoreProgress'
|
||||||
|
|
||||||
// - Import API
|
// - Import API
|
||||||
|
|
||||||
@@ -20,10 +21,6 @@ import { IFindPeopleComponentState } from './IFindPeopleComponentState'
|
|||||||
*/
|
*/
|
||||||
export class FindPeopleComponent extends Component<IFindPeopleComponentProps, IFindPeopleComponentState> {
|
export class FindPeopleComponent extends Component<IFindPeopleComponentProps, IFindPeopleComponentState> {
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component constructor
|
* Component constructor
|
||||||
* @param {object} props is an object properties of component
|
* @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('------------------------')
|
* Scroll loader
|
||||||
console.log(page)
|
*/
|
||||||
console.log('------------------------')
|
scrollLoad = (page: number) => {
|
||||||
|
const {loadPeople} = this.props
|
||||||
|
loadPeople!(page, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount () {
|
|
||||||
this.props.loadPeople!()
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Reneder component DOM
|
* Reneder component DOM
|
||||||
* @return {react element} return the DOM which rendered by component
|
* @return {react element} return the DOM which rendered by component
|
||||||
*/
|
*/
|
||||||
render () {
|
render () {
|
||||||
|
const {hasMorePeople} = this.props
|
||||||
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>
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<InfiniteScroll
|
<InfiniteScroll
|
||||||
pageStart={0}
|
pageStart={0}
|
||||||
loadMore={this.loadItems.bind(this)}
|
loadMore={this.scrollLoad}
|
||||||
hasMore={false}
|
hasMore={hasMorePeople}
|
||||||
loader={loader}>
|
useWindow={true}
|
||||||
|
loader={ <LoadMoreProgressComponent />}
|
||||||
|
>
|
||||||
|
|
||||||
<div className='tracks'>
|
<div className='tracks'>
|
||||||
|
|
||||||
@@ -106,7 +86,7 @@ export class FindPeopleComponent extends Component<IFindPeopleComponentProps, IF
|
|||||||
*/
|
*/
|
||||||
const mapDispatchToProps = (dispatch: any, ownProps: IFindPeopleComponentProps) => {
|
const mapDispatchToProps = (dispatch: any, ownProps: IFindPeopleComponentProps) => {
|
||||||
return {
|
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
|
* @return {object} props of component
|
||||||
*/
|
*/
|
||||||
const mapStateToProps = (state: any, ownProps: IFindPeopleComponentProps) => {
|
const mapStateToProps = (state: any, ownProps: IFindPeopleComponentProps) => {
|
||||||
|
const {people, info} = state.user
|
||||||
return {
|
return {
|
||||||
peopleInfo: state.user.info
|
peopleInfo: info,
|
||||||
|
hasMorePeople: people.hasMoreData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export interface IFindPeopleComponentProps {
|
|||||||
*
|
*
|
||||||
* @memberof IFindPeopleComponentProps
|
* @memberof IFindPeopleComponentProps
|
||||||
*/
|
*/
|
||||||
loadPeople?: () => any
|
loadPeople?: (page: number, limit: number) => any
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Users' profile
|
* Users' profile
|
||||||
@@ -17,4 +17,9 @@ export interface IFindPeopleComponentProps {
|
|||||||
*/
|
*/
|
||||||
peopleInfo?: {[userId: string]: Profile}
|
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 { IFollowersComponentProps } from './IFollowersComponentProps'
|
||||||
import { IFollowersComponentState } from './IFollowersComponentState'
|
import { IFollowersComponentState } from './IFollowersComponentState'
|
||||||
|
import { Circle } from 'core/domain/circles';
|
||||||
|
|
||||||
// - Import API
|
// - Import API
|
||||||
|
|
||||||
@@ -79,10 +80,11 @@ const mapDispatchToProps = (dispatch: any,ownProps: IFollowersComponentProps) =>
|
|||||||
* @return {object} props of component
|
* @return {object} props of component
|
||||||
*/
|
*/
|
||||||
const mapStateToProps = (state: any,ownProps: IFollowersComponentProps) => {
|
const mapStateToProps = (state: any,ownProps: IFollowersComponentProps) => {
|
||||||
|
const {circle, authorize, server} = state
|
||||||
const { uid } = state.authorize
|
const { uid } = state.authorize
|
||||||
const circles = state.circle ? state.circle.userCircles[uid] : {}
|
const circles: { [circleId: string]: Circle } = circle ? (circle.circleList || {}) : {}
|
||||||
return{
|
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 {
|
export interface IFollowersComponentProps {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User followers info
|
* User followers info
|
||||||
*
|
*
|
||||||
* @type {{[userId: string]: UserFollower}}
|
* @type {{[userId: string]: UserTie}}
|
||||||
* @memberof IFindPeopleComponentProps
|
* @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 CircleAPI from 'api/CircleAPI'
|
||||||
import { IFollowingComponentProps } from './IFollowingComponentProps'
|
import { IFollowingComponentProps } from './IFollowingComponentProps'
|
||||||
import { IFollowingComponentState } from './IFollowingComponentState'
|
import { IFollowingComponentState } from './IFollowingComponentState'
|
||||||
|
import { Circle } from 'core/domain/circles';
|
||||||
|
|
||||||
// - Import actions
|
// - Import actions
|
||||||
|
|
||||||
@@ -80,9 +81,10 @@ const mapDispatchToProps = (dispatch: any,ownProp: IFollowingComponentProps) =>
|
|||||||
* @return {object} props of component
|
* @return {object} props of component
|
||||||
*/
|
*/
|
||||||
const mapStateToProps = (state: any,ownProps: IFollowingComponentProps) => {
|
const mapStateToProps = (state: any,ownProps: IFollowingComponentProps) => {
|
||||||
|
const {circle, authorize, server} = state
|
||||||
const { uid } = state.authorize
|
const { uid } = state.authorize
|
||||||
const circles = state.circle ? state.circle.userCircles[uid] : {}
|
const circles: { [circleId: string]: Circle } = circle ? (circle.circleList || {}) : {}
|
||||||
const followingUsers = CircleAPI.getFollowingUsers(circles)
|
const followingUsers = circle ? circle.userTies : {}
|
||||||
return {
|
return {
|
||||||
uid,
|
uid,
|
||||||
circles,
|
circles,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { UserFollower } from 'core/domain/circles'
|
import { UserTie } from 'core/domain/circles'
|
||||||
|
|
||||||
export interface IFollowingComponentProps {
|
export interface IFollowingComponentProps {
|
||||||
|
|
||||||
followingUsers?: {[userId: string]: UserFollower}
|
followingUsers?: {[userId: string]: UserTie}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,7 +106,6 @@ export class HomeComponent extends Component<IHomeComponentProps, IHomeComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount () {
|
componentWillMount () {
|
||||||
|
|
||||||
const {global, clearData, loadData, authed, defaultDataEnable, isVerifide, goTo } = this.props
|
const {global, clearData, loadData, authed, defaultDataEnable, isVerifide, goTo } = this.props
|
||||||
if (!authed) {
|
if (!authed) {
|
||||||
goTo!('/login')
|
goTo!('/login')
|
||||||
@@ -131,7 +130,7 @@ export class HomeComponent extends Component<IHomeComponentProps, IHomeComponent
|
|||||||
* @memberof Home
|
* @memberof Home
|
||||||
*/
|
*/
|
||||||
render () {
|
render () {
|
||||||
const {loaded, authed, mergedPosts} = this.props
|
const {loaded, authed, loadDataStream, mergedPosts, hasMorePosts} = this.props
|
||||||
return (
|
return (
|
||||||
<div id='home'>
|
<div id='home'>
|
||||||
<HomeHeader sidebar={this.state.sidebarOpen} sidebarStatus={this.state.sidebarStatus} />
|
<HomeHeader sidebar={this.state.sidebarOpen} sidebarStatus={this.state.sidebarStatus} />
|
||||||
@@ -153,7 +152,7 @@ export class HomeComponent extends Component<IHomeComponentProps, IHomeComponent
|
|||||||
</SidebarContent>
|
</SidebarContent>
|
||||||
|
|
||||||
<SidebarMain>
|
<SidebarMain>
|
||||||
<HomeRouter enabled={loaded!} data={{mergedPosts}} />
|
<HomeRouter enabled={loaded!} data={{ mergedPosts, loadDataStream, hasMorePosts}} />
|
||||||
</SidebarMain>
|
</SidebarMain>
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
|
|
||||||
@@ -167,12 +166,15 @@ export class HomeComponent extends Component<IHomeComponentProps, IHomeComponent
|
|||||||
const mapDispatchToProps = (dispatch: any, ownProps: IHomeComponentProps) => {
|
const mapDispatchToProps = (dispatch: any, ownProps: IHomeComponentProps) => {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
loadDataStream:
|
||||||
|
(page: number, limit: number) => dispatch(postActions.dbGetPosts(page,limit)),
|
||||||
loadData: () => {
|
loadData: () => {
|
||||||
dispatch(imageGalleryActions.dbGetImageGallery())
|
|
||||||
dispatch(postActions.dbGetPosts())
|
dispatch(postActions.dbGetPosts())
|
||||||
|
dispatch(imageGalleryActions.dbGetImageGallery())
|
||||||
dispatch(userActions.dbGetUserInfo())
|
dispatch(userActions.dbGetUserInfo())
|
||||||
dispatch(notifyActions.dbGetNotifications())
|
dispatch(notifyActions.dbGetNotifications())
|
||||||
dispatch(circleActions.dbGetCircles())
|
dispatch(circleActions.dbGetCircles())
|
||||||
|
dispatch(circleActions.dbGetUserTies())
|
||||||
|
|
||||||
},
|
},
|
||||||
clearData: () => {
|
clearData: () => {
|
||||||
@@ -205,9 +207,10 @@ const mapStateToProps = (state: any, ownProps: IHomeComponentProps) => {
|
|||||||
const { authorize, global, user, post, imageGallery, notify, circle } = state
|
const { authorize, global, user, post, imageGallery, notify, circle } = state
|
||||||
const { uid } = authorize
|
const { uid } = authorize
|
||||||
let mergedPosts = {}
|
let mergedPosts = {}
|
||||||
const circles = circle ? (circle.userCircles[uid] || {}) : {}
|
const circles = circle ? (circle.circleList || {}) : {}
|
||||||
const followingUsers = CircleAPI.getFollowingUsers(circles)
|
const followingUsers = circle ? circle.userTies : {}
|
||||||
const posts = post.userPosts ? post.userPosts[authorize.uid] : {}
|
const posts = post.userPosts ? post.userPosts[authorize.uid] : {}
|
||||||
|
const hasMorePosts = post.stream.hasMoreData
|
||||||
Object.keys(followingUsers).forEach((userId) => {
|
Object.keys(followingUsers).forEach((userId) => {
|
||||||
let newPosts = post.userPosts ? post.userPosts[userId] : {}
|
let newPosts = post.userPosts ? post.userPosts[userId] : {}
|
||||||
_.merge(mergedPosts,newPosts)
|
_.merge(mergedPosts,newPosts)
|
||||||
@@ -219,9 +222,10 @@ const mapStateToProps = (state: any, ownProps: IHomeComponentProps) => {
|
|||||||
mainStyle: global.sidebarMainStyle,
|
mainStyle: global.sidebarMainStyle,
|
||||||
mergedPosts,
|
mergedPosts,
|
||||||
global,
|
global,
|
||||||
|
hasMorePosts,
|
||||||
loaded: user.loaded && post.loaded && imageGallery.loaded && notify.loaded && circle.loaded
|
loaded: user.loaded && post.loaded && imageGallery.loaded && notify.loaded && circle.loaded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// - Connect component to redux store
|
// - 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}
|
* @type {string}
|
||||||
* @memberof IHomeComponentProps
|
* @memberof IHomeComponentProps
|
||||||
*/
|
*/
|
||||||
uid: string
|
uid?: string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merged all users posts to show in stream
|
* Merged all users posts to show in stream
|
||||||
@@ -34,6 +34,11 @@ export interface IHomeComponentProps {
|
|||||||
*/
|
*/
|
||||||
mergedPosts?: {[postId: string]: Post}
|
mergedPosts?: {[postId: string]: Post}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the data for stream
|
||||||
|
*/
|
||||||
|
loadDataStream: (lastPostId: string, page: number, limit: number) => any
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Global state
|
* Global state
|
||||||
*
|
*
|
||||||
@@ -80,6 +85,11 @@ export interface IHomeComponentProps {
|
|||||||
*/
|
*/
|
||||||
goTo?: (url: string) => any
|
goTo?: (url: string) => any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If there is more post {true} or not {false}
|
||||||
|
*/
|
||||||
|
hasMorePosts?: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If all requierment data loaded {true} or not {false}
|
* If all requierment data loaded {true} or not {false}
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ export class HomeHeaderComponent extends Component<IHomeHeaderComponentProps,IHo
|
|||||||
|
|
||||||
styles = {
|
styles = {
|
||||||
toolbarStyle: {
|
toolbarStyle: {
|
||||||
backgroundColor: '',
|
|
||||||
transition: 'all 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms',
|
transition: 'all 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms',
|
||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
fontFamily: 'Roboto, sans-serif',
|
fontFamily: 'Roboto, sans-serif',
|
||||||
@@ -187,7 +186,7 @@ export class HomeHeaderComponent extends Component<IHomeHeaderComponentProps,IHo
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<Toolbar style={this.styles.toolbarStyle as any} className='g__greenBox'>
|
<Toolbar style={this.styles.toolbarStyle as any}>
|
||||||
<EventListener
|
<EventListener
|
||||||
target='window'
|
target='window'
|
||||||
onResize={this.handleResize}
|
onResize={this.handleResize}
|
||||||
|
|||||||
@@ -191,4 +191,4 @@ const mapStateToProps = (state: any) => {
|
|||||||
|
|
||||||
}
|
}
|
||||||
// - Connect commponent to redux store
|
// - 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}
|
* @type {string}
|
||||||
* @memberof IPostComponentProps
|
* @memberof IPostComponentProps
|
||||||
*/
|
*/
|
||||||
avatar: string
|
avatar?: string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User full name
|
* User full name
|
||||||
@@ -105,7 +105,7 @@ export interface IPostComponentProps {
|
|||||||
*
|
*
|
||||||
* @memberof IPostComponentProps
|
* @memberof IPostComponentProps
|
||||||
*/
|
*/
|
||||||
getPostComments: (ownerUserId: string, postId: string) => any
|
getPostComments?: (ownerUserId: string, postId: string) => any
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Commnets
|
* Commnets
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export class PostComponent extends Component<IPostComponentProps,IPostComponentS
|
|||||||
/**
|
/**
|
||||||
* Post text
|
* Post text
|
||||||
*/
|
*/
|
||||||
text: post.body!,
|
text: post.body ? post.body : '',
|
||||||
/**
|
/**
|
||||||
* It's true if whole the text post is visible
|
* 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 mapStateToProps = (state: any, ownProps: IPostComponentProps) => {
|
||||||
const {post, vote, authorize, comment} = state
|
const {post, vote, authorize, comment} = state
|
||||||
const {uid} = authorize
|
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 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 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!]
|
const commentList: { [commentId: string]: Comment } = comment.postComments[ownProps.post.id!]
|
||||||
|
|||||||
@@ -50,12 +50,12 @@ export interface IPostWriteComponentProps {
|
|||||||
/**
|
/**
|
||||||
* The post owner name
|
* The post owner name
|
||||||
*/
|
*/
|
||||||
ownerDisplayName: string
|
ownerDisplayName?: string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Post model
|
* Post model
|
||||||
*/
|
*/
|
||||||
postModel: Post
|
postModel?: Post
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save a post
|
* Save a post
|
||||||
|
|||||||
@@ -49,15 +49,15 @@ export class PostWriteComponent extends Component<IPostWriteComponentProps,IPost
|
|||||||
/**
|
/**
|
||||||
* Post text
|
* Post text
|
||||||
*/
|
*/
|
||||||
postText: this.props.edit ? this.props.text! : '',
|
postText: this.props.edit && postModel ? (postModel.body ? postModel.body! : '' ) : '',
|
||||||
/**
|
/**
|
||||||
* The URL image of the post
|
* 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
|
* 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
|
* 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
|
* 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
|
* 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)
|
}, onRequestClose)
|
||||||
}
|
}
|
||||||
} else { // In edit status we pass post to update functions
|
} else { // In edit status we pass post to update functions
|
||||||
postModel.body = postText
|
postModel!.body = postText
|
||||||
postModel.tags = tags
|
postModel!.tags = tags
|
||||||
postModel.image = image
|
postModel!.image = image
|
||||||
postModel.imageFullPath = imageFullPath
|
postModel!.imageFullPath = imageFullPath
|
||||||
postModel.disableComments = disableComments
|
postModel!.disableComments = disableComments
|
||||||
postModel.disableSharing = disableSharing
|
postModel!.disableSharing = disableSharing
|
||||||
|
|
||||||
update!(postModel, onRequestClose)
|
update!(postModel!, onRequestClose)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,30 +255,34 @@ export class PostWriteComponent extends Component<IPostWriteComponentProps,IPost
|
|||||||
if (!nextProps.open) {
|
if (!nextProps.open) {
|
||||||
const {postModel} = this.props
|
const {postModel} = this.props
|
||||||
this.setState({
|
this.setState({
|
||||||
/**
|
/**
|
||||||
* Post text
|
* Post text
|
||||||
*/
|
*/
|
||||||
postText: this.props.edit ? this.props.text! : '',
|
postText: this.props.edit && postModel ? (postModel.body ? postModel.body! : '' ) : '',
|
||||||
/**
|
/**
|
||||||
* The image of the post
|
* The URL image of the post
|
||||||
*/
|
*/
|
||||||
image: this.props.edit ? this.props.image! : '',
|
image: this.props.edit && postModel ? (postModel.image ? postModel.image! : '' ) : '',
|
||||||
/**
|
/**
|
||||||
* If it's true gallery will be open
|
* 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,
|
galleryOpen: false,
|
||||||
/**
|
/**
|
||||||
* If it's true post button will be disabled
|
* If it's true post button will be disabled
|
||||||
*/
|
*/
|
||||||
disabledPost: true,
|
disabledPost: true,
|
||||||
/**
|
/**
|
||||||
* If it's true comment will be disabled on post
|
* 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
|
* 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
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,4 +79,9 @@ export interface IProfileComponentProps {
|
|||||||
* @memberof IProfileComponentProps
|
* @memberof IProfileComponentProps
|
||||||
*/
|
*/
|
||||||
loadUserInfo: () => any
|
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)'
|
border: '2px solid rgb(255, 255, 255)'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const {loadPosts, hasMorePosts} = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={styles.profile}>
|
<div style={styles.profile}>
|
||||||
@@ -91,7 +92,11 @@ export class ProfileComponent extends Component<IProfileComponentProps,IProfileC
|
|||||||
</div>
|
</div>
|
||||||
<div style={{ height: '24px' }}></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>)
|
||||||
: (<div className='profile__title'>
|
: (<div className='profile__title'>
|
||||||
Nothing shared
|
Nothing shared
|
||||||
@@ -127,6 +132,7 @@ const mapDispatchToProps = (dispatch: any, ownProps: IProfileComponentProps) =>
|
|||||||
const mapStateToProps = (state: any, ownProps: IProfileComponentProps) => {
|
const mapStateToProps = (state: any, ownProps: IProfileComponentProps) => {
|
||||||
const { userId } = ownProps.match.params
|
const { userId } = ownProps.match.params
|
||||||
const {uid} = state.authorize
|
const {uid} = state.authorize
|
||||||
|
const hasMorePosts = state.post.profile.hasMoreData
|
||||||
return {
|
return {
|
||||||
avatar: state.user.info && state.user.info[userId] ? state.user.info[userId].avatar || '' : '',
|
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 || '' : '',
|
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 || '' : '',
|
tagLine: state.user.info && state.user.info[userId] ? state.user.info[userId].tagLine || '' : '',
|
||||||
posts: state.post.userPosts ? state.post.userPosts[userId] : {},
|
posts: state.post.userPosts ? state.post.userPosts[userId] : {},
|
||||||
isAuthedUser: userId === uid,
|
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
|
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
|
* Posts for stream
|
||||||
*
|
*
|
||||||
* @type {{[postId: string]: Post}}
|
* @type {{[postId: string]: Post}}
|
||||||
* @memberof IStreamComponentProps
|
* @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 {
|
export interface IStreamComponentState {
|
||||||
|
|
||||||
@@ -34,7 +35,15 @@ export interface IStreamComponentState {
|
|||||||
divided: boolean
|
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}
|
* @type {string}
|
||||||
* @memberof IStreamComponentState
|
* @memberof IStreamComponentState
|
||||||
|
|||||||
@@ -5,15 +5,18 @@ import { connect } from 'react-redux'
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { Card, CardActions, CardHeader, CardMedia, CardTitle, CardText } from 'material-ui/Card'
|
import { Card, CardActions, CardHeader, CardMedia, CardTitle, CardText } from 'material-ui/Card'
|
||||||
import FlatButton from 'material-ui/FlatButton'
|
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 SvgCamera from 'material-ui/svg-icons/image/photo-camera'
|
||||||
import Paper from 'material-ui/Paper'
|
import Paper from 'material-ui/Paper'
|
||||||
import { List, ListItem } from 'material-ui/List'
|
import { List, ListItem } from 'material-ui/List'
|
||||||
|
import InfiniteScroll from 'react-infinite-scroller'
|
||||||
|
|
||||||
// - Import app components
|
// - Import app components
|
||||||
import PostComponent from 'components/post'
|
import PostComponent from 'components/post'
|
||||||
import PostWriteComponent from 'components/postWrite'
|
import PostWriteComponent from 'components/postWrite'
|
||||||
import UserAvatarComponent from 'components/userAvatar'
|
import UserAvatarComponent from 'components/userAvatar'
|
||||||
|
import LoadMoreProgressComponent from 'layouts/loadMoreProgress'
|
||||||
|
|
||||||
// - Import API
|
// - Import API
|
||||||
import * as PostAPI from 'api/PostAPI'
|
import * as PostAPI from 'api/PostAPI'
|
||||||
@@ -23,6 +26,7 @@ import * as globalActions from 'actions/globalActions'
|
|||||||
|
|
||||||
import { IStreamComponentProps } from './IStreamComponentProps'
|
import { IStreamComponentProps } from './IStreamComponentProps'
|
||||||
import { IStreamComponentState } from './IStreamComponentState'
|
import { IStreamComponentState } from './IStreamComponentState'
|
||||||
|
import { Post } from 'core/domain/posts'
|
||||||
|
|
||||||
// - Create StreamComponent component class
|
// - Create StreamComponent component class
|
||||||
export class StreamComponent extends Component<IStreamComponentProps,IStreamComponentState> {
|
export class StreamComponent extends Component<IStreamComponentProps,IStreamComponentState> {
|
||||||
@@ -82,7 +86,12 @@ export class StreamComponent extends Component<IStreamComponentProps,IStreamComp
|
|||||||
/**
|
/**
|
||||||
* The title of home header
|
* 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`
|
// Binding functions to `this`
|
||||||
@@ -115,13 +124,13 @@ export class StreamComponent extends Component<IStreamComponentProps,IStreamComp
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a list of posts
|
* Create a list of posts
|
||||||
* @return {DOM} posts
|
* @return {DOM} posts
|
||||||
*/
|
*/
|
||||||
postLoad = () => {
|
postLoad = () => {
|
||||||
|
|
||||||
let { posts ,match }: any = this.props
|
let { posts ,match } = this.props
|
||||||
let {tag} = match.params
|
let {tag} = match.params
|
||||||
if (posts === undefined || !(Object.keys(posts).length > 0)) {
|
if (posts === undefined || !(Object.keys(posts).length > 0)) {
|
||||||
|
|
||||||
@@ -139,7 +148,7 @@ export class StreamComponent extends Component<IStreamComponentProps,IStreamComp
|
|||||||
Object.keys(posts).forEach((postId) => {
|
Object.keys(posts).forEach((postId) => {
|
||||||
if (tag) {
|
if (tag) {
|
||||||
let regex = new RegExp('#' + tag,'g')
|
let regex = new RegExp('#' + tag,'g')
|
||||||
let postMatch = posts[postId].body.match(regex)
|
let postMatch = posts[postId].body!.match(regex)
|
||||||
if (postMatch !== null) {
|
if (postMatch !== null) {
|
||||||
parsedPosts.push({ ...posts[postId]})
|
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 () {
|
componentWillMount () {
|
||||||
const {setHomeTitle} = this.props
|
const {setHomeTitle} = this.props
|
||||||
setHomeTitle!()
|
setHomeTitle!()
|
||||||
@@ -188,14 +205,18 @@ export class StreamComponent extends Component<IStreamComponentProps,IStreamComp
|
|||||||
*/
|
*/
|
||||||
render () {
|
render () {
|
||||||
|
|
||||||
let postList: any = this.postLoad()
|
const {tag, displayWriting, hasMorePosts } = this.props
|
||||||
|
const postList = this.postLoad() as {evenPostList: Post[], oddPostList: Post[], divided: boolean} | any
|
||||||
const {tag, displayWriting } = this.props
|
|
||||||
|
|
||||||
return (
|
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 grid__gutters grid__1of2 grid__space-around animate-top'>
|
||||||
|
|
||||||
<div className='grid-cell animate-top' style= {{maxWidth: '530px', minWidth: '280px'}}>
|
<div className='grid-cell animate-top' style= {{maxWidth: '530px', minWidth: '280px'}}>
|
||||||
{displayWriting && !tag
|
{displayWriting && !tag
|
||||||
? (<PostWriteComponent open={this.state.openPostWrite} onRequestClose={this.handleClosePostWrite} edit={false} >
|
? (<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>)
|
||||||
: ''}
|
: ''}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</InfiniteScroll>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -254,6 +276,7 @@ const mapDispatchToProps = (dispatch: any, ownProps: IStreamComponentProps) => {
|
|||||||
* @return {object} props of component
|
* @return {object} props of component
|
||||||
*/
|
*/
|
||||||
const mapStateToProps = (state: any, ownProps: IStreamComponentProps) => {
|
const mapStateToProps = (state: any, ownProps: IStreamComponentProps) => {
|
||||||
|
const {post} = state
|
||||||
return {
|
return {
|
||||||
avatar: state.user.info && state.user.info[state.authorize.uid] ? state.user.info[state.authorize.uid].avatar : '',
|
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 : ''
|
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
|
// - 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 { User } from 'core/domain/users'
|
||||||
import { Circle } from 'core/domain/circles/circle'
|
import { Circle } from 'core/domain/circles/circle'
|
||||||
import { UserFollower } from 'core/domain/circles'
|
import { UserTie } from 'core/domain/circles'
|
||||||
|
|
||||||
export interface IUserBoxComponentProps {
|
export interface IUserBoxComponentProps {
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ export interface IUserBoxComponentProps {
|
|||||||
* @type {User}
|
* @type {User}
|
||||||
* @memberof IUserBoxComponentProps
|
* @memberof IUserBoxComponentProps
|
||||||
*/
|
*/
|
||||||
user: UserFollower
|
user: UserTie
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Circles
|
* Circles
|
||||||
@@ -36,6 +36,11 @@ export interface IUserBoxComponentProps {
|
|||||||
*/
|
*/
|
||||||
userBelongCircles?: string[]
|
userBelongCircles?: string[]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether current user followed this user
|
||||||
|
*/
|
||||||
|
isFollowed: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of circles
|
* The number of circles
|
||||||
*
|
*
|
||||||
@@ -80,7 +85,7 @@ export interface IUserBoxComponentProps {
|
|||||||
*
|
*
|
||||||
* @memberof IUserBoxComponentProps
|
* @memberof IUserBoxComponentProps
|
||||||
*/
|
*/
|
||||||
addFollowingUser?: (cid: string,user: UserFollower) => any
|
addFollowingUser?: (cid: string,user: UserTie) => any
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete
|
* Delete
|
||||||
|
|||||||
@@ -2,12 +2,20 @@
|
|||||||
export interface IUserBoxComponentState {
|
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}
|
* @type {boolean}
|
||||||
* @memberof IUserBoxComponentState
|
* @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
|
* Circle name
|
||||||
@@ -32,4 +40,15 @@ export interface IUserBoxComponentState {
|
|||||||
* @memberof IUserBoxComponentState
|
* @memberof IUserBoxComponentState
|
||||||
*/
|
*/
|
||||||
open: boolean
|
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 MenuItem from 'material-ui/MenuItem'
|
||||||
import Checkbox from 'material-ui/Checkbox'
|
import Checkbox from 'material-ui/Checkbox'
|
||||||
import TextField from 'material-ui/TextField'
|
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 app components
|
||||||
import UserAvatar from 'components/userAvatar'
|
import UserAvatar from 'components/userAvatar'
|
||||||
|
|
||||||
// - Import API
|
// - Import API
|
||||||
import CircleAPI from 'api/CircleAPI'
|
import CircleAPI from 'api/CircleAPI'
|
||||||
|
import StringAPI from 'api/StringAPI'
|
||||||
|
|
||||||
// - Import actions
|
// - Import actions
|
||||||
import * as circleActions from 'actions/circleActions'
|
import * as circleActions from 'actions/circleActions'
|
||||||
@@ -24,21 +29,22 @@ import * as circleActions from 'actions/circleActions'
|
|||||||
import { IUserBoxComponentProps } from './IUserBoxComponentProps'
|
import { IUserBoxComponentProps } from './IUserBoxComponentProps'
|
||||||
import { IUserBoxComponentState } from './IUserBoxComponentState'
|
import { IUserBoxComponentState } from './IUserBoxComponentState'
|
||||||
import { User } from 'core/domain/users'
|
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
|
* Create component class
|
||||||
*/
|
*/
|
||||||
export class UserBoxComponent extends Component<IUserBoxComponentProps,IUserBoxComponentState> {
|
export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBoxComponentState> {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
/**
|
/**
|
||||||
* User identifier
|
* User identifier
|
||||||
*/
|
*/
|
||||||
userId: PropTypes.string,
|
userId: PropTypes.string,
|
||||||
/**
|
/**
|
||||||
* User information
|
* User information
|
||||||
*/
|
*/
|
||||||
user: PropTypes.object
|
user: PropTypes.object
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -53,207 +59,297 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps,IUserBoxC
|
|||||||
},
|
},
|
||||||
followButton: {
|
followButton: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
bottom: '8px',
|
bottom: '30px',
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0
|
right: 0
|
||||||
|
},
|
||||||
|
dialog: {
|
||||||
|
width: '',
|
||||||
|
maxWidth: '280px',
|
||||||
|
borderRadius: '4px'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component constructor
|
* Component constructor
|
||||||
* @param {object} props is an object properties of component
|
* @param {object} props is an object properties of component
|
||||||
*/
|
*/
|
||||||
constructor (props: IUserBoxComponentProps) {
|
constructor (props: IUserBoxComponentProps) {
|
||||||
super(props)
|
super(props)
|
||||||
|
const { userBelongCircles, circles } = this.props
|
||||||
// Defaul state
|
// Defaul state
|
||||||
this.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,
|
open: false,
|
||||||
/**
|
/**
|
||||||
* The value of circle input
|
* The value of circle input
|
||||||
*/
|
*/
|
||||||
circleName: '',
|
circleName: '',
|
||||||
/**
|
/**
|
||||||
* It will be true if the text field for adding group is empty
|
* It will be true if the text field for adding group is empty
|
||||||
*/
|
*/
|
||||||
disabledAddCircle: true
|
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.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)
|
this.handleFollowUser = this.handleFollowUser.bind(this)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleFollowUser = (checked: boolean,cid: string) => {
|
/**
|
||||||
const {userId,user} = this.props
|
* Handle follow user
|
||||||
const {avatar,fullName} = user
|
*/
|
||||||
|
handleFollowUser = (checked: boolean, cid: string) => {
|
||||||
|
const { userId, user } = this.props
|
||||||
|
const { avatar, fullName } = user
|
||||||
if (checked) {
|
if (checked) {
|
||||||
this.props.addFollowingUser!(cid,{avatar,userId,fullName})
|
this.props.addFollowingUser!(cid, { avatar, userId, fullName })
|
||||||
} else {
|
} else {
|
||||||
this.props.deleteFollowingUser!(cid,userId)
|
this.props.deleteFollowingUser!(cid, userId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle create circle
|
* Handle request close for add circle box
|
||||||
*
|
*/
|
||||||
*
|
onRequestCloseAddCircle = () => {
|
||||||
* @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 = () => {
|
|
||||||
this.setState({
|
this.setState({
|
||||||
open: false
|
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 = () => {
|
circleList = () => {
|
||||||
let { circles, userId, userBelongCircles } = this.props
|
let { circles, userId, userBelongCircles } = this.props
|
||||||
|
|
||||||
if (circles) {
|
if (circles) {
|
||||||
|
|
||||||
return Object.keys(circles).map((key, index) => {
|
return Object.keys(circles).map((circleId, index) => {
|
||||||
if (key.trim() !== '-Followers') {
|
const {selectedCircles} = this.state
|
||||||
let isBelong = userBelongCircles!.indexOf(key) > -1
|
let isBelong = selectedCircles!.indexOf(circleId) > -1
|
||||||
|
// Create checkbox for selected/unselected circle
|
||||||
return <Checkbox
|
return <Checkbox
|
||||||
key={key}
|
key={circleId}
|
||||||
style={{ padding: '10px' }}
|
style={{ padding: '10px' }}
|
||||||
label={circles![key].name}
|
label={circles![circleId].name}
|
||||||
labelStyle={{
|
labelStyle={{
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
textOverflow: 'ellipsis',
|
textOverflow: 'ellipsis',
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
width: '100%'
|
width: '100%'
|
||||||
}}
|
}}
|
||||||
onCheck={(evt,checked) => this.handleFollowUser(checked,key)}
|
onCheck={(event: object, isInputChecked: boolean) => this.handleSelectCircle(event, isInputChecked, circleId)}
|
||||||
checked={isBelong}
|
checked={isBelong}
|
||||||
/>
|
/>
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reneder component DOM
|
* Check if the the selected circles changed
|
||||||
* @return {react element} return the DOM which rendered by component
|
*/
|
||||||
*/
|
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 () {
|
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 (
|
return (
|
||||||
<Paper style={this.styles.paper} zDepth={1} className='grid-cell'>
|
<Paper style={this.styles.paper} zDepth={1} className='grid-cell'>
|
||||||
<div style={{
|
<div style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'flex-start',
|
justifyContent: 'flex-start',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
padding: '30px'
|
paddingTop: 20
|
||||||
|
|
||||||
}}>
|
}}>
|
||||||
<div onClick={() => this.props.goTo!(`/${this.props.userId}`)} style={{cursor: 'pointer'}}>
|
<div onClick={() => this.props.goTo!(`/${this.props.userId}`)} style={{ cursor: 'pointer' }}>
|
||||||
<UserAvatar
|
<UserAvatar
|
||||||
fullName={this.props.fullName!}
|
fullName={this.props.fullName!}
|
||||||
fileName={this.props.avatar!}
|
fileName={this.props.avatar!}
|
||||||
size={90}
|
size={90}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div onClick={() => this.props.goTo!(`/${this.props.userId}`)} className='people__name' style={{cursor: 'pointer'}}>
|
<div onClick={() => this.props.goTo!(`/${this.props.userId}`)} className='people__name' style={{ cursor: 'pointer' }}>
|
||||||
<div>
|
<div>
|
||||||
{this.props.user.fullName}
|
{this.props.user.fullName}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={this.styles.followButton as any}>
|
<div style={this.styles.followButton as any}>
|
||||||
<FlatButton
|
<FlatButton
|
||||||
label={(this.props.belongCirclesCount && this.props.belongCirclesCount < 1) ? 'Follow'
|
label={!isFollowed ? 'Follow'
|
||||||
: (this.props.belongCirclesCount! > 1 ? `${this.props.belongCirclesCount} Circles` : ((this.props.firstBelongCircle) ? this.props.firstBelongCircle.name : 'Follow'))}
|
: (this.props.belongCirclesCount! > 1 ? `${this.props.belongCirclesCount} Circles` : ((this.props.firstBelongCircle) ? this.props.firstBelongCircle.name : 'Follow'))}
|
||||||
primary={true}
|
primary={true}
|
||||||
onTouchTap={this.handleTouchTap}
|
onTouchTap={this.onFollowUser}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Popover
|
<Dialog
|
||||||
open={this.state.open}
|
key={this.props.userId || 0}
|
||||||
anchorEl={this.state.anchorEl}
|
actions={writeActions}
|
||||||
anchorOrigin={{ horizontal: 'left', vertical: 'bottom' }}
|
modal={false}
|
||||||
targetOrigin={{ horizontal: 'left', vertical: 'top' }}
|
open={this.state.open}
|
||||||
onRequestClose={this.handleRequestClose}
|
contentStyle={this.styles.dialog}
|
||||||
animation={PopoverAnimationVertical}
|
onRequestClose={this.onRequestCloseAddCircle}
|
||||||
>
|
overlayStyle={{ background: 'rgba(0,0,0,0.12)' }}
|
||||||
<Menu >
|
bodyStyle={{ padding: 0 }}
|
||||||
<div style={{
|
autoDetectWindowHeight={false}
|
||||||
position: 'relative',
|
actionsContainerStyle={{ borderTop: '1px solid rgb(224, 224, 224)' }}
|
||||||
display: 'block',
|
|
||||||
maxHeight: '220px'
|
|
||||||
}}>
|
|
||||||
<div style={{ overflowY: 'auto', height: '100%' }}>
|
|
||||||
{this.circleList()}
|
|
||||||
|
|
||||||
</div>
|
>
|
||||||
</div>
|
<div style={{
|
||||||
<div style={{ padding: '10px' }}>
|
position: 'relative',
|
||||||
<TextField
|
display: 'block',
|
||||||
hintText='Group name'
|
maxHeight: '220px'
|
||||||
onChange={this.handleChangeName}
|
}}>
|
||||||
value={this.state.circleName}
|
<div style={{ overflowY: 'auto', height: '100%' }}>
|
||||||
/><br />
|
{this.circleList()}
|
||||||
<FlatButton label='ADD' primary={true} disabled={this.state.disabledAddCircle} onClick={this.handleCreateCricle} />
|
|
||||||
</div>
|
</div>
|
||||||
</Menu>
|
</div>
|
||||||
</Popover>
|
<div style={{ padding: '10px' }}>
|
||||||
</Paper>
|
<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) => {
|
const mapDispatchToProps = (dispatch: Function, ownProps: IUserBoxComponentProps) => {
|
||||||
return {
|
return {
|
||||||
createCircle: (name: string) => dispatch(circleActions.dbAddCircle(name)),
|
createCircle: (name: string) => dispatch(circleActions.dbAddCircle(name)),
|
||||||
addFollowingUser: (cid: string,user: UserFollower) => dispatch(circleActions.dbAddFollowingUser(cid,user)),
|
addFollowingUser: (circleIds: string[], user: UserTie) => dispatch(circleActions.dbUpdateUserInCircles(circleIds, user)),
|
||||||
deleteFollowingUser: (cid: string ,followingId: string) => dispatch(circleActions.dbDeleteFollowingUser(cid,followingId)),
|
deleteFollowingUser: (cid: string, followingId: string) => dispatch(circleActions.dbDeleteFollowingUser(followingId)),
|
||||||
goTo: (url: string) => dispatch(push(url))
|
goTo: (url: string) => dispatch(push(url))
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -281,13 +377,17 @@ const mapDispatchToProps = (dispatch: Function, ownProps: IUserBoxComponentProps
|
|||||||
* @return {object} props of component
|
* @return {object} props of component
|
||||||
*/
|
*/
|
||||||
const mapStateToProps = (state: any, ownProps: IUserBoxComponentProps) => {
|
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 {
|
return {
|
||||||
circles: circles,
|
isFollowed,
|
||||||
userBelongCircles: userBelongCircles || [],
|
circles,
|
||||||
|
userBelongCircles,
|
||||||
belongCirclesCount: userBelongCircles.length || 0,
|
belongCirclesCount: userBelongCircles.length || 0,
|
||||||
firstBelongCircle: userBelongCircles ? (circles ? circles[userBelongCircles[0]] : {}) : {},
|
firstBelongCircle: userBelongCircles ? (circles ? circles[userBelongCircles[0]] : {}) : {},
|
||||||
avatar: state.user.info && state.user.info[ownProps.userId] ? state.user.info[ownProps.userId].avatar || '' : '',
|
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 { User } from 'core/domain/users'
|
||||||
import { UserFollower } from 'core/domain/circles'
|
import { UserTie } from 'core/domain/circles'
|
||||||
|
|
||||||
export interface IUserBoxListComponentProps {
|
export interface IUserBoxListComponentProps {
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ export interface IUserBoxListComponentProps {
|
|||||||
* @type {{[userId: string]: User}}
|
* @type {{[userId: string]: User}}
|
||||||
* @memberof IUserBoxListComponentProps
|
* @memberof IUserBoxListComponentProps
|
||||||
*/
|
*/
|
||||||
users: {[userId: string]: UserFollower}
|
users: {[userId: string]: UserTie}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User identifier
|
* User identifier
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { List } from 'material-ui/List'
|
|||||||
import CircleComponent from 'components/circle'
|
import CircleComponent from 'components/circle'
|
||||||
import { IYourCirclesComponentProps } from './IYourCirclesComponentProps'
|
import { IYourCirclesComponentProps } from './IYourCirclesComponentProps'
|
||||||
import { IYourCirclesComponentState } from './IYourCirclesComponentState'
|
import { IYourCirclesComponentState } from './IYourCirclesComponentState'
|
||||||
|
import { Circle } from 'core/domain/circles';
|
||||||
|
|
||||||
// - Import API
|
// - Import API
|
||||||
|
|
||||||
@@ -97,10 +98,12 @@ const mapDispatchToProps = (dispatch: Function, ownProps: IYourCirclesComponentP
|
|||||||
* @return {object} props of component
|
* @return {object} props of component
|
||||||
*/
|
*/
|
||||||
const mapStateToProps = (state: any, ownProps: IYourCirclesComponentProps) => {
|
const mapStateToProps = (state: any, ownProps: IYourCirclesComponentProps) => {
|
||||||
|
const {circle, authorize, server} = state
|
||||||
const { uid } = state.authorize
|
const { uid } = state.authorize
|
||||||
|
const circles: { [circleId: string]: Circle } = circle ? (circle.circleList || {}) : {}
|
||||||
return {
|
return {
|
||||||
uid,
|
uid,
|
||||||
circles: state.circle ? state.circle.userCircles[uid] : {}
|
circles
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export enum CircleActionType {
|
export enum CircleActionType {
|
||||||
|
|
||||||
ADD_CIRCLE = 'ADD_CIRCLE',
|
ADD_CIRCLE = 'ADD_CIRCLE',
|
||||||
DELETE_CIRCLE = 'DELETE_CIRCLE',
|
DELETE_CIRCLE = 'DELETE_CIRCLE',
|
||||||
UPDATE_CIRCLE = 'UPDATE_CIRCLE',
|
UPDATE_CIRCLE = 'UPDATE_CIRCLE',
|
||||||
@@ -9,4 +9,13 @@ export enum CircleActionType {
|
|||||||
CLOSE_CIRCLE_SETTINGS = 'CLOSE_CIRCLE_SETTINGS',
|
CLOSE_CIRCLE_SETTINGS = 'CLOSE_CIRCLE_SETTINGS',
|
||||||
ADD_FOLLOWING_USER = 'ADD_FOLLOWING_USER',
|
ADD_FOLLOWING_USER = 'ADD_FOLLOWING_USER',
|
||||||
DELETE_FOLLOWING_USER = 'DELETE_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 {
|
export enum PostActionType {
|
||||||
|
|
||||||
ADD_IMAGE_POST = 'ADD_IMAGE_POST',
|
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_VIDEO_POST = 'ADD_VIDEO_POST',
|
||||||
ADD_POST = 'ADD_POST',
|
ADD_POST = 'ADD_POST',
|
||||||
UPDATE_POST = 'UPDATE_POST',
|
UPDATE_POST = 'UPDATE_POST',
|
||||||
@@ -8,4 +16,3 @@
|
|||||||
ADD_LIST_POST = 'ADD_LIST_POST',
|
ADD_LIST_POST = 'ADD_LIST_POST',
|
||||||
CLEAR_ALL_DATA_POST = 'CLEAR_ALL_DATA_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',
|
CLEAR_ALL_DATA_USER = 'CLEAR_ALL_DATA_USER',
|
||||||
OPEN_EDIT_PROFILE = 'OPEN_EDIT_PROFILE',
|
OPEN_EDIT_PROFILE = 'OPEN_EDIT_PROFILE',
|
||||||
CLOSE_EDIT_PROFILE = 'CLOSE_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'
|
import { BaseDomain } from 'core/domain/common'
|
||||||
|
|
||||||
export class Circle extends BaseDomain {
|
export class Circle extends BaseDomain {
|
||||||
@@ -35,12 +34,9 @@ export class Circle extends BaseDomain {
|
|||||||
*/
|
*/
|
||||||
public name: string
|
public name: string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The users in a circle
|
* Whether circle setting is open
|
||||||
*
|
*/
|
||||||
* @type {string}
|
public openCircleSettings?: boolean
|
||||||
* @memberof User
|
|
||||||
*/
|
|
||||||
public users: {[userId: string]: UserFollower}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {Circle} from './circle'
|
import { Circle } from './circle'
|
||||||
import {UserFollower} from './userFollower'
|
import { UserTie } from './UserTie'
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Circle,
|
Circle,
|
||||||
UserFollower
|
UserTie
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
import { BaseDomain } from 'core/domain/common'
|
import { BaseDomain } from 'core/domain/common'
|
||||||
|
|
||||||
export class UserFollower extends BaseDomain {
|
export class UserTie extends BaseDomain {
|
||||||
|
|
||||||
|
constructor (
|
||||||
/**
|
/**
|
||||||
* User identifier
|
* User identifier
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof UserFollower
|
* @memberof UserTie
|
||||||
*/
|
*/
|
||||||
userId?: string
|
public userId?: string,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Circle creation date time
|
* Circle creation date time
|
||||||
@@ -16,30 +17,38 @@ export class UserFollower extends BaseDomain {
|
|||||||
* @type {Date}
|
* @type {Date}
|
||||||
* @memberof Circle
|
* @memberof Circle
|
||||||
*/
|
*/
|
||||||
public creationDate?: number
|
public creationDate?: number,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User full name
|
* User full name
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof UserFollower
|
* @memberof UserTie
|
||||||
*/
|
*/
|
||||||
public fullName: string
|
public fullName?: string,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Avatar URL address
|
* Avatar URL address
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof UserFollower
|
* @memberof UserTie
|
||||||
*/
|
*/
|
||||||
public avatar: string
|
public avatar?: string,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If following user approved {true} or not {false}
|
* If following user approved {true} or not {false}
|
||||||
*
|
*
|
||||||
* @type {Boolean}
|
* @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'
|
import { BaseDomain } from 'core/domain/common'
|
||||||
|
|
||||||
export class User extends BaseDomain {
|
export class User extends BaseDomain {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Full name of user
|
* Full name of user
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof User
|
* @memberof User
|
||||||
*/
|
*/
|
||||||
public fullName: string
|
public fullName: string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User avatar address
|
* User avatar address
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof User
|
* @memberof User
|
||||||
*/
|
*/
|
||||||
public avatar: string
|
public avatar: string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Email of the user
|
* Email of the user
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof User
|
* @memberof User
|
||||||
*/
|
*/
|
||||||
public email?: string | null
|
public email?: string | null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Password of the user
|
* Password of the user
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof User
|
* @memberof User
|
||||||
*/
|
*/
|
||||||
public password?: string | null
|
public password?: string | null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User identifier
|
* User identifier
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof User
|
* @memberof User
|
||||||
*/
|
*/
|
||||||
public userId?: string | null
|
public userId?: string | null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User creation date
|
* User creation date
|
||||||
*
|
*
|
||||||
* @type {number}
|
* @type {number}
|
||||||
* @memberof User
|
* @memberof User
|
||||||
*/
|
*/
|
||||||
public creationDate: number
|
public creationDate: number
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,6 @@ import { BaseDomain } from 'core/domain/common'
|
|||||||
|
|
||||||
export class Vote extends BaseDomain {
|
export class Vote extends BaseDomain {
|
||||||
|
|
||||||
/**
|
|
||||||
* Vote identifier
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof Vote
|
|
||||||
*/
|
|
||||||
public id?: string | null
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Post identifire which vote on
|
* Post identifire which vote on
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
//#region Interfaces
|
//#region Interfaces
|
||||||
|
|
||||||
import { IServiceProvider } from 'core/factories'
|
import { IServiceProvider } from 'core/factories'
|
||||||
|
import { injectable } from 'inversify'
|
||||||
import {
|
import {
|
||||||
IAuthorizeService,
|
IAuthorizeService,
|
||||||
ICircleService,
|
ICircleService,
|
||||||
@@ -33,7 +34,7 @@ import {
|
|||||||
} from 'data/firestoreClient/services'
|
} from 'data/firestoreClient/services'
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
@injectable()
|
||||||
export class ServiceProvide implements IServiceProvider {
|
export class ServiceProvide implements IServiceProvider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { User } from 'core/domain/users'
|
import { User } from 'core/domain/users'
|
||||||
import { Circle, UserFollower } from 'core/domain/circles'
|
import { Circle, UserTie } from 'core/domain/circles'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Circle service interface
|
* Circle service interface
|
||||||
@@ -10,8 +10,6 @@ import { Circle, UserFollower } from 'core/domain/circles'
|
|||||||
export interface ICircleService {
|
export interface ICircleService {
|
||||||
|
|
||||||
addCircle: (userId: string, circle: Circle) => Promise<string>
|
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>
|
updateCircle: (userId: string, circleId: string, circle: Circle) => Promise<void>
|
||||||
deleteCircle: (userId: string, circleId: string) => Promise<void>
|
deleteCircle: (userId: string, circleId: string) => Promise<void>
|
||||||
getCircles: (userId: string) => Promise<{ [circleId: string]: Circle }>
|
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 { ICircleService } from './ICircleService'
|
||||||
|
import { IUserTieService } from './IUserTieService'
|
||||||
|
|
||||||
export {
|
export {
|
||||||
ICircleService
|
ICircleService,
|
||||||
|
IUserTieService
|
||||||
}
|
}
|
||||||
@@ -13,6 +13,6 @@ export interface ICommentService {
|
|||||||
addComment: (comment: Comment) => Promise<string>
|
addComment: (comment: Comment) => Promise<string>
|
||||||
getComments: (postId: string, callback: (resultComments: { [postId: string]: { [commentId: string]: Comment } }) => void) => void
|
getComments: (postId: string, callback: (resultComments: { [postId: string]: { [commentId: string]: Comment } }) => void) => void
|
||||||
updateComment: (comment: Comment) => Promise<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>
|
addPost: (post: Post) => Promise<string>
|
||||||
updatePost: (post: Post) => Promise<void>
|
updatePost: (post: Post) => Promise<void>
|
||||||
deletePost: (postId: string) => 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>
|
getPostById: (postId: string) => Promise<Post>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,5 +9,6 @@ import { User, Profile } from 'core/domain/users'
|
|||||||
export interface IUserService {
|
export interface IUserService {
|
||||||
getUserProfile: (userId: string) => Promise<Profile>
|
getUserProfile: (userId: string) => Promise<Profile>
|
||||||
updateUserProfile: (userId: string, profile: Profile) => Promise<void>
|
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 {
|
export interface IVoteService {
|
||||||
addVote: (vote: Vote) => Promise<string>
|
addVote: (vote: Vote) => Promise<string>
|
||||||
getVotes: (postId: string) => Promise<{[postId: string]: {[voteId: string]: Vote}}>
|
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 { OAuthType } from 'core/domain/authorize/oauthType'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
import { injectable } from 'inversify'
|
||||||
/**
|
/**
|
||||||
* Firbase authorize service
|
* Firbase authorize service
|
||||||
*
|
*
|
||||||
@@ -17,6 +18,7 @@ import moment from 'moment'
|
|||||||
* @class AuthorizeService
|
* @class AuthorizeService
|
||||||
* @implements {IAuthorizeService}
|
* @implements {IAuthorizeService}
|
||||||
*/
|
*/
|
||||||
|
@injectable()
|
||||||
export class AuthorizeService implements IAuthorizeService {
|
export class AuthorizeService implements IAuthorizeService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -215,6 +217,8 @@ export class AuthorizeService implements IAuthorizeService {
|
|||||||
return new Promise<RegisterUserResult>((resolve,reject) => {
|
return new Promise<RegisterUserResult>((resolve,reject) => {
|
||||||
db.doc(`userInfo/${userId}`).set(
|
db.doc(`userInfo/${userId}`).set(
|
||||||
{
|
{
|
||||||
|
id: userId,
|
||||||
|
state: 'active',
|
||||||
avatar,
|
avatar,
|
||||||
fullName,
|
fullName,
|
||||||
creationDate: moment().unix(),
|
creationDate: moment().unix(),
|
||||||
|
|||||||
@@ -3,8 +3,9 @@ import { firebaseRef, firebaseAuth, db } from 'data/firestoreClient'
|
|||||||
|
|
||||||
import { SocialError } from 'core/domain/common'
|
import { SocialError } from 'core/domain/common'
|
||||||
import { ICircleService } from 'core/services/circles'
|
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 { User } from 'core/domain/users'
|
||||||
|
import { injectable } from 'inversify'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Firbase circle service
|
* Firbase circle service
|
||||||
@@ -13,12 +14,13 @@ import { User } from 'core/domain/users'
|
|||||||
* @class CircleService
|
* @class CircleService
|
||||||
* @implements {ICircleService}
|
* @implements {ICircleService}
|
||||||
*/
|
*/
|
||||||
|
@injectable()
|
||||||
export class CircleService implements ICircleService {
|
export class CircleService implements ICircleService {
|
||||||
|
|
||||||
public addCircle: (userId: string, circle: Circle)
|
public addCircle: (userId: string, circle: Circle)
|
||||||
=> Promise<string> = (userId, circle) => {
|
=> Promise<string> = (userId, circle) => {
|
||||||
return new Promise<string>((resolve,reject) => {
|
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) => {
|
circleRef.then((result) => {
|
||||||
resolve(result.id as string)
|
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)
|
public updateCircle: (userId: string, circleId: string, circle: Circle)
|
||||||
=> Promise<void> = (userId, circleId, circle) => {
|
=> Promise<void> = (userId, circleId, circle) => {
|
||||||
return new Promise<void>((resolve,reject) => {
|
return new Promise<void>((resolve,reject) => {
|
||||||
@@ -71,7 +36,7 @@ export class CircleService implements ICircleService {
|
|||||||
const batch = db.batch()
|
const batch = db.batch()
|
||||||
const circleRef = db.doc(`users/${userId}/circles/${circleId}`)
|
const circleRef = db.doc(`users/${userId}/circles/${circleId}`)
|
||||||
|
|
||||||
batch.update(circleRef,circle)
|
batch.update(circleRef,{...circle})
|
||||||
batch.commit().then(() => {
|
batch.commit().then(() => {
|
||||||
resolve()
|
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 { SocialError } from 'core/domain/common'
|
||||||
import { ICommentService } from 'core/services/comments'
|
import { ICommentService } from 'core/services/comments'
|
||||||
import { Comment } from 'core/domain/comments'
|
import { Comment } from 'core/domain/comments'
|
||||||
|
import { injectable } from 'inversify'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Firbase comment service
|
* Firbase comment service
|
||||||
@@ -13,42 +14,20 @@ import { Comment } from 'core/domain/comments'
|
|||||||
* @class CommentService
|
* @class CommentService
|
||||||
* @implements {ICommentService}
|
* @implements {ICommentService}
|
||||||
*/
|
*/
|
||||||
|
@injectable()
|
||||||
export class CommentService implements ICommentService {
|
export class CommentService implements ICommentService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add comment
|
||||||
|
*
|
||||||
|
* @memberof CommentService
|
||||||
|
*/
|
||||||
public addComment: (comment: Comment)
|
public addComment: (comment: Comment)
|
||||||
=> Promise<string> = (comment) => {
|
=> Promise<string> = (comment) => {
|
||||||
return new Promise<string>((resolve,reject) => {
|
return new Promise<string>((resolve,reject) => {
|
||||||
const postRef = db.doc(`posts/${comment.postId}`)
|
let commentRef = db.collection('comments')
|
||||||
let commentRef = postRef.collection('comments')
|
|
||||||
commentRef.add(comment).then((result) => {
|
commentRef.add(comment).then((result) => {
|
||||||
resolve(result.id)
|
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) => {
|
.catch((error: any) => {
|
||||||
reject(new SocialError(error.code,error.message))
|
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)
|
public getComments: (postId: string, callback: (resultComments: { [postId: string]: { [commentId: string]: Comment } }) => void)
|
||||||
=> void = (postId, callback) => {
|
=> void = (postId, callback) => {
|
||||||
let commentsRef = db.doc(`posts/${postId}`).collection(`comments`)
|
let commentsRef = db.collection(`comments`).where('postId', '==', postId)
|
||||||
commentsRef.onSnapshot((snapshot) => {
|
commentsRef.onSnapshot((snapshot) => {
|
||||||
let parsedData: {[postId: string]: {[commentId: string]: Comment}} = {[postId]: {}}
|
let parsedData: {[postId: string]: {[commentId: string]: Comment}} = {[postId]: {}}
|
||||||
snapshot.forEach((result) => {
|
snapshot.forEach((result) => {
|
||||||
@@ -73,13 +57,18 @@ export class CommentService implements ICommentService {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update comment
|
||||||
|
*
|
||||||
|
* @memberof CommentService
|
||||||
|
*/
|
||||||
public updateComment: (comment: Comment)
|
public updateComment: (comment: Comment)
|
||||||
=> Promise<void> = (comment) => {
|
=> Promise<void> = (comment) => {
|
||||||
return new Promise<void>((resolve,reject) => {
|
return new Promise<void>((resolve,reject) => {
|
||||||
const batch = db.batch()
|
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(() => {
|
batch.commit().then(() => {
|
||||||
resolve()
|
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) => {
|
return new Promise<void>((resolve,reject) => {
|
||||||
const batch = db.batch()
|
const commentCollectionRef = db.collection(`comments`)
|
||||||
const postRef = db.doc(`posts/${postId}`)
|
const commentRef = commentCollectionRef.doc(commentId)
|
||||||
const commentRef = postRef.collection(`comments`).doc(commentId)
|
|
||||||
|
|
||||||
|
const batch = db.batch()
|
||||||
batch.delete(commentRef)
|
batch.delete(commentRef)
|
||||||
batch.commit().then(() => {
|
batch.commit().then(() => {
|
||||||
resolve()
|
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) => {
|
.catch((error: any) => {
|
||||||
reject(new SocialError(error.code,error.message))
|
reject(new SocialError(error.code,error.message))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { firebaseRef, firebaseAuth } from 'data/firebaseClient'
|
|||||||
|
|
||||||
import { SocialError } from 'core/domain/common'
|
import { SocialError } from 'core/domain/common'
|
||||||
import { ICommonService } from 'core/services/common'
|
import { ICommonService } from 'core/services/common'
|
||||||
|
import { injectable } from 'inversify'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Firbase common service
|
* Firbase common service
|
||||||
@@ -11,6 +12,7 @@ import { ICommonService } from 'core/services/common'
|
|||||||
* @class CommonService
|
* @class CommonService
|
||||||
* @implements {ICommonService}
|
* @implements {ICommonService}
|
||||||
*/
|
*/
|
||||||
|
@injectable()
|
||||||
export class CommonService implements ICommonService {
|
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