[Next Version] Realat to #5 #6 #9 #15 #17 #20 #23 #24 #27 #35 #36 #42

This commit is contained in:
Qolzam
2018-01-14 15:10:00 +07:00
parent e38dbc9fd3
commit 051cfa6f07
59 changed files with 1570 additions and 495 deletions

119
README.md
View File

@@ -6,12 +6,13 @@
</p>
<!-- Name -->
<h1 align="center">
<a href="https://github.com/Qolzam/react-social-network">React Social Network</a>
<a href="https://github.com/Qolzam/react-social-network">React Social Network </a>:rocket:<span style="font-variant-caps: petite-caps;font-size: 30px;font-weight: 100;"> Version NEXT! </span>:rocket:
</h1>
[![Gitter](https://badges.gitter.im/react-social-network/Lobby.svg)](https://gitter.im/react-social-network/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
The React Social Network is an open source project relying on [React](https://facebook.github.io/react/docs/hello-world.html) a powerful javascript library for building the user interface. In this project, I tried to show some features of react/react components as a social network.
The React Social Network is an open source project relying on [React](https://facebook.github.io/react/docs/hello-world.html) a powerful javascript library for building the user interface. In this project, I tried to show some features of react/react components as a social network.
The structure of this project give the ability to devoloper to develop their project on thier own idea and environment.
<p align="center">
<a href="http://greensocial.herokuapp.com/">
@@ -27,9 +28,9 @@ For those who prefer writing code by typescript, now React Social Network suppor
This project adheres to the Contributor Covenant [code of conduct](https://github.com/Qolzam/react-social-network/blob/master/CODE_OF_CONDUCT.md).
By participating, you are expected to uphold this code. Please report unacceptable behavior to amir.gholzam@live.com.
## DEMO
## Example
[Green Open Social](http://greensocial.herokuapp.com)
[Love Open Social](https://love-social.firebaseapp.com)
## Required Knowledge
@@ -39,44 +40,37 @@ I recommend that you get to know React before using React Social Network. React
## Document
Use [Documentation](https://qolzam.gitbooks.io/react-social-network/) to find out more details about this project.
## Features
* [TypeScript](https://www.typescriptlang.org/) TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
* [React](https://facebook.github.io/react/docs/hello-world.html) A javascript library for building user interfaces.
* [Redux](http://redux.js.org/) is a predictable state container for JavaScript apps.
* [Material-UI](http://www.material-ui.com/#/) A Set of React Components that Implement Google's Material Design.
* [react-redux](https://github.com/reactjs/react-redux) Official React bindings for Redux.
* [Firebase](https://firebase.google.com/) products like Analytics, Realtime Database, Messaging, and Crash Reporting let you move quickly and focus on your users.
* [redux-thunk](https://github.com/gaearon/redux-thunk) Redux Thunk middleware allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. The inner function receives the store methods dispatch and getState as parameters.
* [Express](https://expressjs.com/) Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.
* [React Router V4](https://github.com/ReactTraining/react-router) for routing website location
* [Sass](http://sass-lang.com/) CSS with superpowers. Sass boasts more features and abilities than any other CSS extension language out there.
* [Webpack](https://webpack.js.org/) for bundling code
## In my todo list
* Documentation
* Testing
* Security issues
* Performance
* Add some features and solving bugs
* Sharing post in social itself and other socials
* Add link feature to post
* Add vido post
* Add image gallery post
* Search post and people
...
Comming soon :) ...
# Prerequisites
## Road map
1. Support Firebase/Firestore -> on developing
2. Support AWS -> on developing
3. Support Azure
4. Support ASP.NET -> on developing
## Getting Started
These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system.
### Prerequisites
Install [NodeJs](https://nodejs.org/en/)
#### Note
# Installing
- If you're using Windows you should install all node-gyp dependencies with following commands:
[![Build social network in 5 minutes](https://img.youtube.com/vi/E12PNKKjzqA/0.jpg)](https://www.youtube.com/watch?v=E12PNKKjzqA)
`$ npm install --global --production windows-build-tools`
and then install the package
`$ npm install --global node-gyp`
### Installing
## Install back-end server/serverless
Comming soon :) ...
1. Fork the [react-social-network](https://github.com/Qolzam/react-social-network) repository on Github
2. Clone your fork to your local machine `git clone git@github.com:<yourname>/react-social-network.git`
@@ -101,31 +95,56 @@ I recommend that you get to know React before using React Social Network. React
5. Installing all nodejs modules:
`npm install`
6. Rub webpack to build bundle file
`webpack`
5. Running server:
`node server.js`
6. Go ahead ;)
`npm start`
# Warning
- If you're using Windows you should install all node-gyp dependencies with following commands:
`$ npm install --global --production windows-build-tools`
and then install the package
`$ npm install --global node-gyp`
## Deployment
Follow [firebase instruction](https://firebase.google.com/docs/hosting/deploying)
`firebase deploy`
## Contribute
## Built With
[React Social Network](http://greensocial.herokuapp.com/) has been made by love. I planed to build a back-end for this project and improve the performance as I process all procedures on the front-end side. If you'd like to help,
* [TypeScript](https://www.typescriptlang.org/) TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
* [JSX/TSX](https://jsx.github.io/) This project support both *.jsx and *.tsx files. JSX is a statically-typed, object-oriented programming language designed to run on modern web browsers. Being developed at DeNA as a research project, the language has following characteristics.
* [React](https://facebook.github.io/react/docs/hello-world.html) A javascript library for building user interfaces.
* [Redux](http://redux.js.org/) is a predictable state container for JavaScript apps.
* [Material-UI](http://www.material-ui.com/#/) A Set of React Components that Implement Google's Material Design.
* [react-redux](https://github.com/reactjs/react-redux) Official React bindings for Redux.
* [Firebase](https://firebase.google.com/) products like Analytics, Realtime Database, Messaging, and Crash Reporting let you move quickly and focus on your users.
* [redux-thunk](https://github.com/gaearon/redux-thunk) Redux Thunk middleware allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. The inner function receives the store methods dispatch and getState as parameters.
* [Express](https://expressjs.com/) Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.
* [React Router V4](https://github.com/ReactTraining/react-router) for routing website location
* [Sass](http://sass-lang.com/) CSS with superpowers. Sass boasts more features and abilities than any other CSS extension language out there.
* [Webpack](https://webpack.js.org/) for bundling code
## Contributing
[React Social Network](https://love-social.firebaseapp.com) has been made by love. I planed to build a back-end for this project and improve the performance as I process all procedures on the front-end side. If you'd like to help,
check out the [document](https://qolzam.gitbooks.io/react-social-network/).
I'd greatly appreciate any [contribution](https://github.com/Qolzam/react-social-network/blob/master/CONTRIBUTING.md)
you make. :)
# Authors
## Versioning
We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/Qolzam/react-social-network/tags).
## Authors
- Amir Movahedi
- See also the list of [contributors](https://github.com/Qolzam/react-social-network/contributors) who participated in this project.
# License
## License
This project is licensed under the MIT License - see the [LICENSE](https://github.com/Qolzam/react-social-network/blob/master/LICENSE) file for details
## Acknowledgments
* React
* Firebase
* JavaScript
* TypeScript

View File

@@ -6,12 +6,13 @@
</p>
<!-- Name -->
<h1 align="center">
<a href="https://github.com/Qolzam/react-social-network">React Social Network</a>
<a href="https://github.com/Qolzam/react-social-network">React Social Network </a>:rocket:<span style="font-variant-caps: petite-caps;font-size: 30px;font-weight: 100;"> Version NEXT! </span>:rocket:
</h1>
[![Gitter](https://badges.gitter.im/react-social-network/Lobby.svg)](https://gitter.im/react-social-network/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
The React Social Network is an open source project relying on [React](https://facebook.github.io/react/docs/hello-world.html) a powerful javascript library for building the user interface. In this project, I tried to show some features of react/react components as a social network.
The React Social Network is an open source project relying on [React](https://facebook.github.io/react/docs/hello-world.html) a powerful javascript library for building the user interface. In this project, I tried to show some features of react/react components as a social network.
The structure of this project give the ability to devoloper to develop their project on thier own idea and environment.
<p align="center">
<a href="http://greensocial.herokuapp.com/">
@@ -27,9 +28,9 @@ For those who prefer writing code by typescript, now React Social Network suppor
This project adheres to the Contributor Covenant [code of conduct](https://github.com/Qolzam/react-social-network/blob/master/CODE_OF_CONDUCT.md).
By participating, you are expected to uphold this code. Please report unacceptable behavior to amir.gholzam@live.com.
## DEMO
## Example
[Green Open Social](http://greensocial.herokuapp.com)
[Love Open Social](https://love-social.firebaseapp.com)
## Required Knowledge
@@ -39,44 +40,37 @@ I recommend that you get to know React before using React Social Network. React
## Document
Use [Documentation](https://qolzam.gitbooks.io/react-social-network/) to find out more details about this project.
## Features
* [TypeScript](https://www.typescriptlang.org/) TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
* [React](https://facebook.github.io/react/docs/hello-world.html) A javascript library for building user interfaces.
* [Redux](http://redux.js.org/) is a predictable state container for JavaScript apps.
* [Material-UI](http://www.material-ui.com/#/) A Set of React Components that Implement Google's Material Design.
* [react-redux](https://github.com/reactjs/react-redux) Official React bindings for Redux.
* [Firebase](https://firebase.google.com/) products like Analytics, Realtime Database, Messaging, and Crash Reporting let you move quickly and focus on your users.
* [redux-thunk](https://github.com/gaearon/redux-thunk) Redux Thunk middleware allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. The inner function receives the store methods dispatch and getState as parameters.
* [Express](https://expressjs.com/) Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.
* [React Router V4](https://github.com/ReactTraining/react-router) for routing website location
* [Sass](http://sass-lang.com/) CSS with superpowers. Sass boasts more features and abilities than any other CSS extension language out there.
* [Webpack](https://webpack.js.org/) for bundling code
## In my todo list
* Documentation
* Testing
* Security issues
* Performance
* Add some features and solving bugs
* Sharing post in social itself and other socials
* Add link feature to post
* Add vido post
* Add image gallery post
* Search post and people
...
Comming soon :) ...
# Prerequisites
## Road map
1. Support Firebase/Firestore -> on developing
2. Support AWS -> on developing
3. Support Azure
4. Support ASP.NET -> on developing
## Getting Started
These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system.
### Prerequisites
Install [NodeJs](https://nodejs.org/en/)
#### Note
# Installing
- If you're using Windows you should install all node-gyp dependencies with following commands:
[![Build social network in 5 minutes](https://img.youtube.com/vi/E12PNKKjzqA/0.jpg)](https://www.youtube.com/watch?v=E12PNKKjzqA)
`$ npm install --global --production windows-build-tools`
and then install the package
`$ npm install --global node-gyp`
### Installing
## Install back-end server/serverless
Comming soon :) ...
1. Fork the [react-social-network](https://github.com/Qolzam/react-social-network) repository on Github
2. Clone your fork to your local machine `git clone git@github.com:<yourname>/react-social-network.git`
@@ -101,31 +95,56 @@ I recommend that you get to know React before using React Social Network. React
5. Installing all nodejs modules:
`npm install`
6. Rub webpack to build bundle file
`webpack`
5. Running server:
`node server.js`
6. Go ahead ;)
`npm start`
# Warning
- If you're using Windows you should install all node-gyp dependencies with following commands:
`$ npm install --global --production windows-build-tools`
and then install the package
`$ npm install --global node-gyp`
## Deployment
Follow [firebase instruction](https://firebase.google.com/docs/hosting/deploying)
`firebase deploy`
## Contribute
## Built With
[React Social Network](http://greensocial.herokuapp.com/) has been made by love. I planed to build a back-end for this project and improve the performance as I process all procedures on the front-end side. If you'd like to help,
* [TypeScript](https://www.typescriptlang.org/) TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
* [JSX/TSX](https://jsx.github.io/) This project support both *.jsx and *.tsx files. JSX is a statically-typed, object-oriented programming language designed to run on modern web browsers. Being developed at DeNA as a research project, the language has following characteristics.
* [React](https://facebook.github.io/react/docs/hello-world.html) A javascript library for building user interfaces.
* [Redux](http://redux.js.org/) is a predictable state container for JavaScript apps.
* [Material-UI](http://www.material-ui.com/#/) A Set of React Components that Implement Google's Material Design.
* [react-redux](https://github.com/reactjs/react-redux) Official React bindings for Redux.
* [Firebase](https://firebase.google.com/) products like Analytics, Realtime Database, Messaging, and Crash Reporting let you move quickly and focus on your users.
* [redux-thunk](https://github.com/gaearon/redux-thunk) Redux Thunk middleware allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. The inner function receives the store methods dispatch and getState as parameters.
* [Express](https://expressjs.com/) Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.
* [React Router V4](https://github.com/ReactTraining/react-router) for routing website location
* [Sass](http://sass-lang.com/) CSS with superpowers. Sass boasts more features and abilities than any other CSS extension language out there.
* [Webpack](https://webpack.js.org/) for bundling code
## Contributing
[React Social Network](https://love-social.firebaseapp.com) has been made by love. I planed to build a back-end for this project and improve the performance as I process all procedures on the front-end side. If you'd like to help,
check out the [document](https://qolzam.gitbooks.io/react-social-network/).
I'd greatly appreciate any [contribution](https://github.com/Qolzam/react-social-network/blob/master/CONTRIBUTING.md)
you make. :)
# Authors
## Versioning
We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/Qolzam/react-social-network/tags).
## Authors
- Amir Movahedi
- See also the list of [contributors](https://github.com/Qolzam/react-social-network/contributors) who participated in this project.
# License
## License
This project is licensed under the MIT License - see the [LICENSE](https://github.com/Qolzam/react-social-network/blob/master/LICENSE) file for details
## Acknowledgments
* React
* Firebase
* JavaScript
* TypeScript

View File

@@ -2,22 +2,6 @@
Is a decoupled layer of interfaces to data and/or functionality of one or more components.
## CircleAPI.jsx
We provided some functions for doing some procedures on user circles.
```javascript
getUserBelongCircles = (circles,followingId) => {}
```
To get circles which the user is added in. `circles` is the parameter that we want to know if user is exist in any of them or not. `followingId` is the parameter that show the use identifier who we are looking for in `circles` parameter.
```javascript
getFollowingUsers = (circles) => {}
```
Get the user who are in circles. `circles` is the paramater that we get users from.
## FileAPI.jsx
A set of functions for working with files.

View File

@@ -39,7 +39,7 @@
"node-sass": "^4.5.2",
"npm": "^5.6.0",
"prop-types": "^15.6.0",
"react": "^16.0.0",
"react": "^16.2.0",
"react-addons-test-utils": "^15.6.2",
"react-avatar-editor": "^10.3.0",
"react-dom": "^16.0.0",
@@ -68,6 +68,7 @@
"devDependencies": {
"@types/lodash": "^4.14.77",
"@types/material-ui": "^0.18.2",
"@types/moment": "^2.13.0",
"@types/node": "^8.0.33",
"@types/prop-types": "^15.5.2",
"@types/react": "^16.0.10",

View File

@@ -14,12 +14,17 @@ import * as globalActions from 'actions/globalActions'
import * as postActions from 'actions/postActions'
import * as userActions from 'actions/userActions'
import * as notifyActions from 'actions/notifyActions'
import * as serverActions from 'actions/serverActions'
import { IServiceProvider, ServiceProvide } from 'core/factories'
import { ICircleService } from 'core/services/circles'
import { SocialProviderTypes } from 'core/socialProviderTypes'
import { provider } from '../socialEngine'
import { IUserTieService } from 'core/services/circles'
import StringAPI from 'api/StringAPI'
import { ServerRequestStatusType } from 'actions/serverRequestStatusType'
import { ServerRequestType } from 'constants/serverRequestType'
import { ServerRequestModel } from 'models/server/serverRequestModel'
/**
* Get service providers
@@ -39,7 +44,9 @@ export let dbAddCircle = (circleName: string) => {
let uid: string = getState().authorize.uid
let circle: Circle = {
creationDate: moment().unix(),
name: circleName
name: circleName,
isSystem : false,
ownerId: uid
}
return circleService.addCircle(uid, circle).then((circleKey: string) => {
circle.id = circleKey
@@ -51,6 +58,60 @@ export let dbAddCircle = (circleName: string) => {
}
}
/**
* Add referer user to the `Following` circle of current user
*/
export const dbFollowUser = (followingCircleId: string, userFollowing: UserTie) => {
return (dispatch: Function, getState: Function) => {
const state = getState()
let uid: string = state.authorize.uid
let user: User = { ...state.user.info[uid], userId: uid }
// Set server request status to {Sent} for following user
const followReqestModel = createFollowRequest(userFollowing.userId!)
dispatch(serverActions.sendRequest(followReqestModel))
// Call server API
return userTieService.tieUseres(
{ userId: user.userId!, fullName: user.fullName, avatar: user.avatar, approved: false },
{ userId: userFollowing.userId!, fullName: userFollowing.fullName, avatar: userFollowing.avatar, approved: false },
[followingCircleId]
)
.then(() => {
dispatch(addFollowingUser(
new UserTie(
userFollowing.userId!,
moment().unix(),
userFollowing.fullName,
userFollowing.avatar,
false,
[followingCircleId]
)))
// Set server request status to {OK} for following user
followReqestModel.status = ServerRequestStatusType.OK
dispatch(serverActions.sendRequest(followReqestModel))
// Send notification
dispatch(notifyActions.dbAddNotification(
{
description: `${user.fullName} follow you.`,
url: `/${uid}`,
notifyRecieverUserId: userFollowing.userId as string,
notifierUserId: uid,
isSeen: false
}))
}, (error: SocialError) => {
dispatch(globalActions.showErrorMessage(error.message))
// Set server request status to {Error} for following user
followReqestModel.status = ServerRequestStatusType.Error
dispatch(serverActions.sendRequest(followReqestModel))
})
}
}
/**
* Update user in circle/circles
*/
@@ -60,7 +121,14 @@ export let dbUpdateUserInCircles = (circleIdList: string[], userFollowing: UserT
let uid: string = state.authorize.uid
let user: User = { ...state.user.info[uid], userId: uid }
return userTieService.tieUseres(
// Set server request status to {Sent}
const addToCircleRequest = createAddToCircleRequest(userFollowing.userId!)
dispatch(serverActions.sendRequest(addToCircleRequest))
dispatch(globalActions.showMasterLoading())
// Call server API
return userTieService.updateUsersTie(
{ userId: user.userId!, fullName: user.fullName, avatar: user.avatar, approved: false },
{ userId: userFollowing.userId!, fullName: userFollowing.fullName, avatar: userFollowing.avatar, approved: false },
circleIdList
@@ -76,17 +144,23 @@ export let dbUpdateUserInCircles = (circleIdList: string[], userFollowing: UserT
circleIdList
)))
dispatch(notifyActions.dbAddNotification(
{
description: `${user.fullName} follow you.`,
url: `/${uid}`,
notifyRecieverUserId: userFollowing.userId as string,
notifierUserId: uid,
isSeen: false
}))
// Set server request status to {OK}
addToCircleRequest.status = ServerRequestStatusType.OK
dispatch(serverActions.sendRequest(addToCircleRequest))
dispatch(globalActions.hideMasterLoading())
// Close select circle box
dispatch(closeSelectCircleBox(userFollowing.userId!))
}, (error: SocialError) => {
dispatch(globalActions.showErrorMessage(error.message))
dispatch(globalActions.hideMasterLoading())
// Set server request status to {Error}
addToCircleRequest.status = ServerRequestStatusType.Error
dispatch(serverActions.sendRequest(addToCircleRequest))
})
}
}
@@ -99,11 +173,36 @@ export let dbDeleteFollowingUser = (userFollowingId: string) => {
let uid: string = getState().authorize.uid
// Set server request status to {Sent}
const deleteFollowingUserRequest = createdeleteFollowingUserRequest(userFollowingId)
dispatch(serverActions.sendRequest(deleteFollowingUserRequest))
dispatch(globalActions.showMasterLoading())
// Call server API
return userTieService.removeUsersTie(uid, userFollowingId)
.then(() => {
dispatch(deleteFollowingUser(userFollowingId))
dispatch(globalActions.hideMasterLoading())
// Close select circle box
dispatch(closeSelectCircleBox(userFollowingId))
// Set server request status to {OK}
deleteFollowingUserRequest.status = ServerRequestStatusType.OK
dispatch(serverActions.sendRequest(deleteFollowingUserRequest))
}, (error: SocialError) => {
dispatch(globalActions.showErrorMessage(error.message))
dispatch(globalActions.hideMasterLoading())
// Close select circle box
dispatch(closeSelectCircleBox(userFollowingId))
// Set server request status to {Error}
deleteFollowingUserRequest.status = ServerRequestStatusType.Error
dispatch(serverActions.sendRequest(deleteFollowingUserRequest))
})
}
}
@@ -120,7 +219,8 @@ export const dbUpdateCircle = (newCircle: Circle) => {
// Write the new data simultaneously in the list
let circle: Circle = getState().circle.userTies[uid][newCircle.id!]
let updatedCircle: Circle = {
name: newCircle.name || circle.name
name: newCircle.name || circle.name,
isSystem : false
}
return circleService.updateCircle(uid, newCircle.id!, circle)
.then(() => {
@@ -198,10 +298,10 @@ export const dbGetFollowers = () => {
return (dispatch: any, getState: Function) => {
let uid: string = getState().authorize.uid
if (uid) {
userTieService.getUserTies(uid).then((result) => {
userTieService.getUserTieSender(uid).then((result) => {
dispatch(userActions.addPeopleInfo(result as any))
dispatch(addUserTies(result))
dispatch(addUserTieds(result))
})
.catch((error: SocialError) => {
@@ -230,6 +330,45 @@ export const dbGetCirclesByUserId = (uid: string) => {
}
}
/**
* Create follow user serevr request model
*/
const createFollowRequest = (userFollowingId: string) => {
const requestId = StringAPI.createServerRequestId(ServerRequestType.CircleFollowUser, userFollowingId)
return new ServerRequestModel(
ServerRequestType.CircleFollowUser,
requestId,
'',
ServerRequestStatusType.Sent
)
}
/**
* Create add referer user to circle serevr request model
*/
const createAddToCircleRequest = (userFollowingId: string) => {
const requestId = StringAPI.createServerRequestId(ServerRequestType.CircleAddToCircle, userFollowingId)
return new ServerRequestModel(
ServerRequestType.CircleAddToCircle,
requestId,
'',
ServerRequestStatusType.Sent
)
}
/**
* Create delete referer user serevr request model
*/
const createdeleteFollowingUserRequest = (userFollowingId: string) => {
const requestId = StringAPI.createServerRequestId(ServerRequestType.CircleDeleteFollowingUser, userFollowingId)
return new ServerRequestModel(
ServerRequestType.CircleDeleteFollowingUser,
requestId,
'',
ServerRequestStatusType.Sent
)
}
/* _____________ CRUD State _____________ */
/**
@@ -396,6 +535,49 @@ export const showFollowingUserLoading = (userId: string) => {
}
/**
* Set current user selected circles for referer user
*/
export const setSelectedCircles = (userId: string, circleList: string[]) => {
return {
type: CircleActionType.SET_SELECTED_CIRCLES_USER_BOX_COMPONENT,
payload: { userId, circleList }
}
}
/**
* Remove current user selected circles for referer user
*/
export const removeSelectedCircles = (userId: string) => {
return {
type: CircleActionType.REMOVE_SELECTED_CIRCLES_USER_BOX_COMPONENT,
payload: { userId }
}
}
/**
* Open select circle box
*/
export const openSelectCircleBox = (userId: string) => {
return {
type: CircleActionType.OPEN_SELECT_CIRCLES_USER_BOX_COMPONENT,
payload: { userId}
}
}
/**
* Close select circle box
*/
export const closeSelectCircleBox = (userId: string) => {
return {
type: CircleActionType.CLOSE_SELECT_CIRCLES_USER_BOX_COMPONENT,
payload: { userId}
}
}
/**
* Hide loading on following user
*/
@@ -405,4 +587,4 @@ export const hideFollowingUserLoading = (userId: string) => {
payload: { userId }
}
}
}

View File

@@ -97,7 +97,7 @@ export const dbGetComments = (ownerUserId: string, postId: string) => {
}
const desiredComments = comments[postId]
if (desiredComments && Object.keys(desiredComments).length > 0) {
if (desiredComments) {
commentsCount = Object.keys(desiredComments).length
let sortedObjects = desiredComments as any
// Sort posts with creation date

View File

@@ -5,6 +5,50 @@ import { GlobalActionType } from 'constants/globalActionType'
import * as postActions from 'actions/postActions'
import * as commentActions from 'actions/commentActions'
import * as userActions from 'actions/userActions'
import * as serverActions from 'actions/serverActions'
import { ICommonService } from 'core/services/common/ICommonService'
import { provider } from 'src/socialEngine'
import { SocialProviderTypes } from 'core/socialProviderTypes'
import { Feed, SocialError } from 'core/domain/common'
import { ServerRequestType } from 'constants/serverRequestType'
import StringAPI from 'api/StringAPI'
import { ServerRequestModel } from 'models/server'
import { ServerRequestStatusType } from 'actions/serverRequestStatusType'
/**
* Get service providers
*/
const commonService: ICommonService = provider.get<ICommonService>(SocialProviderTypes.CommonService)
/**
* Add a normal feed
* @param {any} newFeed
* @param {Function} callBack
*/
export let dbSendFeed = (newFeed: Feed) => {
return (dispatch: any, getState: Function) => {
let uid: string = getState().authorize.uid
// Set server request status to {Sent}
const feedbackRequest = createFeedbackRequest(uid)
dispatch(serverActions.sendRequest(feedbackRequest))
return commonService.addFeed(newFeed).then(() => {
// Set server request status to {OK}
feedbackRequest.status = ServerRequestStatusType.OK
dispatch(serverActions.sendRequest(feedbackRequest))
})
.catch((error: SocialError) => {
dispatch(showErrorMessage(error.message))
// Set server request status to {Error}
feedbackRequest.status = ServerRequestStatusType.Error
dispatch(serverActions.sendRequest(feedbackRequest))
})
}
}
/**
* Progress change
@@ -14,7 +58,7 @@ import * as userActions from 'actions/userActions'
export const progressChange = (percent: number, visible: Boolean) => {
return {
type: GlobalActionType.PROGRESS_CHANGE,
payload: {percent, visible}
payload: { percent, visible }
}
}
@@ -23,7 +67,7 @@ export const progressChange = (percent: number, visible: Boolean) => {
* Default data loaded status will be true
*/
export const defaultDataEnable = () => {
return{
return {
type: GlobalActionType.DEFAULT_DATA_ENABLE
}
}
@@ -33,21 +77,21 @@ export const defaultDataEnable = () => {
* @param {boolean} status
*/
export const defaultDataDisable = () => {
return{
return {
type: GlobalActionType.DEFAULT_DATA_DISABLE
}
}
// - Show notification of request
export const showNotificationRequest = () => {
return{
return {
type: GlobalActionType.SHOW_SEND_REQUEST_MESSAGE_GLOBAL
}
}
// - Show notification of success
export const showNotificationSuccess = () => {
return{
return {
type: GlobalActionType.SHOW_REQUEST_SUCCESS_MESSAGE_GLOBAL
}
}
@@ -57,7 +101,7 @@ export const showNotificationSuccess = () => {
*/
export const hideMessage = () => {
hideTopLoading()
return{
return {
type: GlobalActionType.HIDE_MESSAGE_GLOBAL
}
@@ -68,23 +112,6 @@ export const hideMessage = () => {
* @param {string} message
*/
export const showErrorMessage = (message: string) => {
const appElement = document.getElementById('app')
const masterElement = document.getElementById('master')
const container = document.createElement('div')
const div = document.createElement('div')
div.innerHTML = message
container.style.position = '100000'
container.style.position = 'fixed'
container.style.backgroundColor = '#32c3e4b8'
container.style.width = '100%'
container.style.height = '100%'
container.style.display = 'flex'
container.style.alignItems = 'center'
container.style.alignItems = 'center'
container.style.flexDirection = 'row'
container.appendChild(div)
appElement!.insertBefore(container, masterElement)
return {
type: GlobalActionType.SHOW_ERROR_MESSAGE_GLOBAL,
payload: message
@@ -95,8 +122,8 @@ export const showErrorMessage = (message: string) => {
/**
* Set header title
*/
export const setHeaderTitleOpt = (callerKey: string,payload: any) => {
return (dispatch: any,getState: Function) => {
export const setHeaderTitleOpt = (callerKey: string, payload: any) => {
return (dispatch: any, getState: Function) => {
switch (callerKey) {
case 'profile':
const userName = getState().user.info && getState().user.info[payload] ? getState().user.info[payload].fullName : ''
@@ -114,7 +141,7 @@ export const setHeaderTitleOpt = (callerKey: string,payload: any) => {
* Set header title
*/
export const setHeaderTitle = (text: string) => {
return{
return {
type: GlobalActionType.SET_HEADER_TITLE,
payload: text
}
@@ -125,7 +152,7 @@ export const setHeaderTitle = (text: string) => {
* Open post write
*/
export const openPostWrite = () => {
return{
return {
type: GlobalActionType.OPEN_POST_WRITE
}
@@ -135,7 +162,7 @@ export const openPostWrite = () => {
* Close post write
*/
export const closePostWrite = () => {
return{
return {
type: GlobalActionType.CLOSE_POST_WRITE
}
@@ -145,7 +172,7 @@ export const closePostWrite = () => {
* Show top loading
*/
export const showTopLoading = () => {
return{
return {
type: GlobalActionType.SHOW_TOP_LOADING
}
@@ -155,17 +182,57 @@ export const showTopLoading = () => {
* Hide top loading
*/
export const hideTopLoading = () => {
return{
return {
type: GlobalActionType.HIDE_TOP_LOADING
}
}
/**
* Show master loading
*/
export const showMasterLoading = () => {
return {
type: GlobalActionType.SHOW_MASTER_LOADING
}
}
/**
* Show send feedback
*/
export const showSendFeedback = () => {
return {
type: GlobalActionType.SHOW_SEND_FEEDBACK
}
}
/**
* Hide send feedback
*/
export const hideSendFeedback = () => {
return {
type: GlobalActionType.HIDE_SEND_FEEDBACK
}
}
/**
* Hide master loading
*/
export const hideMasterLoading = () => {
return {
type: GlobalActionType.HIDE_MASTER_LOADING
}
}
/**
* Store temp data
*/
export const temp = (data: any) => {
return{
return {
type: GlobalActionType.TEMP,
payload: data
}
@@ -176,7 +243,7 @@ export const temp = (data: any) => {
* Clear temp data
*/
export const clearTemp = () => {
return{
return {
type: GlobalActionType.CLEAR_TEMP
}
@@ -185,7 +252,43 @@ export const clearTemp = () => {
// - Load data for guest
export const loadDataGuest = () => {
// tslint:disable-next-line:no-empty
return (dispatch: any,getState: Function) => {
return (dispatch: any, getState: Function) => {
}
}
/**
* Show error report dialog
*/
const showErrorReport = (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)
}
/**
* Create send feedback serevr request model
*/
const createFeedbackRequest = (userId: string) => {
const requestId = StringAPI.createServerRequestId(ServerRequestType.CommonSendFeedback, userId)
return new ServerRequestModel(
ServerRequestType.CommonSendFeedback,
requestId,
'',
ServerRequestStatusType.Sent
)
}

View File

@@ -15,7 +15,7 @@ import { SocialError } from 'core/domain/common/socialError'
* @param {Request} request
*/
export const sendRequest = (request: ServerRequestModel) => {
return { type: ServerActionType.ADD_REQUEST, payload: request }
return { type: ServerActionType.ADD_REQUEST, payload: {request} }
}

View File

@@ -1,47 +0,0 @@
import { Circle, UserTie } from 'core/domain/circles'
/**
* Get the circles' id which the specify users is in that circle
* @param {object} circles
* @param {string} followingId
*/
export const getUserBelongCircles = (circles: {[circleId: string]: Circle},followingId: string) => {
let userBelongCircles: string[] = []
Object.keys(circles).forEach((cid) => {
if (cid.trim() !== '-Followers' && circles[cid].users) {
let isExist = Object.keys(circles[cid].users).indexOf(followingId) > -1
if (isExist) {
userBelongCircles.push(cid)
}
}
})
return userBelongCircles
}
/**
* Get the following users
* @param {object} circles
*/
export const getFollowingUsers = (circles: {[circleId: string]: Circle}) => {
let followingUsers: {[userId: string]: UserTie} = {}
Object.keys(circles).forEach((cid) => {
if (cid.trim() !== '-Followers' && circles[cid].users) {
Object.keys(circles[cid].users).forEach((userId) => {
let isExist = Object.keys(followingUsers).indexOf(userId) > -1
if (!isExist) {
followingUsers[userId] = {
...circles[cid].users[userId]
}
}
})
}
})
return followingUsers
}
export default {
getUserBelongCircles,
getFollowingUsers
}

View File

@@ -1,17 +1,15 @@
import * as moment from 'moment'
/**
* Log the data
* @param title log title
* @param data log data object
*/
const logger = (title: string, data: any, trace?: boolean) => {
const logger = (title: string, data: any) => {
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}`)
console.log(`\n\n%c ======= ${title} ======= %c${moment().format('HH:mm:ss SSS')} \n`, `color:${getRandomColor()};font-size:15`
, `color:${getRandomColor()};font-size:15`, data,`\n\n =========================================`)
}
/**

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<!--
2018-1-14: Created with FontForge (http://fontforge.org)
-->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<metadata>
Created by FontForge 20160405 at Sun Jan 14 05:05:09 2018
By Apache
Copyright (c) 2018, Apache
</metadata>
<defs>
<font id="Flaticon" horiz-adv-x="512" >
<font-face
font-family="Flaticon"
font-weight="400"
font-stretch="normal"
units-per-em="512"
panose-1="2 0 5 3 0 0 0 0 0 0"
ascent="448"
descent="-64"
bbox="0 -63.999 512 448"
underline-thickness="25.6"
underline-position="-51.2"
unicode-range="U+0020-F106"
/>
<missing-glyph />
<glyph glyph-name="space" unicode=" " horiz-adv-x="200"
/>
<glyph glyph-name="uniF100" unicode="&#xf100;"
d="M345.6 217.601c-21.248 0 -38.3994 17.1514 -38.3994 38.3994s17.1514 38.4004 38.3994 38.4004s38.4004 -17.1523 38.4004 -38.4004s-17.1523 -38.3994 -38.4004 -38.3994zM166.4 217.601c-21.248 0 -38.4004 17.1514 -38.4004 38.3994s17.1523 38.4004 38.4004 38.4004
s38.3994 -17.1523 38.3994 -38.4004s-17.1514 -38.3994 -38.3994 -38.3994zM255.999 140.8c59.6484 0 110.208 -37.2471 130.688 -89.5996h-261.376c20.4795 52.3525 71.0391 89.5996 130.688 89.5996zM255.872 448c141.439 0 256.128 -114.561 256.128 -255.999
c0 -141.439 -114.688 -256 -256.128 -256s-255.872 114.561 -255.872 256c0 141.438 114.432 255.999 255.872 255.999zM255.999 -12.7998c113.153 0 204.801 91.6484 204.801 204.801c0 113.151 -91.6484 204.799 -204.801 204.799
c-113.151 0 -204.8 -91.6465 -204.8 -204.799c0 -113.153 91.6484 -204.801 204.8 -204.801z" />
<glyph glyph-name="uniF106" unicode="&#xf106;"
d="M255.999 51.2002c-59.6465 0 -110.335 37.376 -130.815 89.5996h261.631c-20.4785 -52.2236 -71.167 -89.5996 -130.815 -89.5996zM255.872 448c141.439 0 256.128 -114.561 256.128 -255.999c0 -141.439 -114.688 -256 -256.128 -256s-255.872 114.561 -255.872 256
c0 141.438 114.432 255.999 255.872 255.999zM255.999 -12.7998c113.153 0 204.801 91.6484 204.801 204.801c0 113.151 -91.6484 204.799 -204.801 204.799c-113.151 0 -204.8 -91.6465 -204.8 -204.799c0 -113.153 91.6484 -204.801 204.8 -204.801zM176.128 244.735
l-27.1357 -27.1348l-27.2646 27.1348l54.4004 54.2725l54.2715 -54.2725l-27.1348 -27.1348zM281.601 244.735l54.2705 54.2725l54.4014 -54.2725l-27.2646 -27.1348l-27.1367 27.1348l-27.1357 -27.1348z" />
<glyph glyph-name="uniF104" unicode="&#xf104;"
d="M166.4 217.601c-21.248 0 -38.4004 17.1514 -38.4004 38.3994s17.1523 38.4004 38.4004 38.4004s38.3994 -17.1523 38.3994 -38.4004s-17.1514 -38.3994 -38.3994 -38.3994zM345.6 217.601c-21.248 0 -38.3994 17.1514 -38.3994 38.3994s17.1514 38.4004 38.3994 38.4004
s38.4004 -17.1523 38.4004 -38.4004s-17.1523 -38.3994 -38.4004 -38.3994zM255.744 448c141.567 0 256.256 -114.688 256.256 -255.999c0 -141.312 -114.688 -256 -256.256 -256c-141.312 0 -255.744 114.688 -255.744 256c0 141.312 114.432 255.999 255.744 255.999z
M255.999 -12.7998c113.153 0 204.801 91.6484 204.801 204.801c0 113.151 -91.6484 204.799 -204.801 204.799c-113.151 0 -204.8 -91.6465 -204.8 -204.799c0 -113.153 91.6484 -204.801 204.8 -204.801zM255.999 140.8c59.6484 0 110.593 -37.2471 131.071 -89.5996
h-42.8789c-17.792 30.4639 -50.4326 51.2002 -88.1924 51.2002c-37.7588 0 -70.3984 -20.7363 -88.1924 -51.2002h-42.8799c20.4805 52.3525 71.4238 89.5996 131.072 89.5996z" />
<glyph glyph-name="uniF101" unicode="&#xf101;"
d="M148.992 192.001l-27.2646 27.1348l27.2646 27.1357l-27.2646 27.1367l27.2646 27.2646l27.1357 -27.2646l27.1367 27.2646l27.1348 -27.2646l-27.1348 -27.1367l27.1348 -27.1357l-27.1348 -27.1348l-27.1367 27.1348zM255.999 140.8
c59.6484 0 110.337 -37.376 130.817 -89.5996h-261.633c20.4795 52.2236 71.167 89.5996 130.815 89.5996zM363.008 300.673l27.2646 -27.2646l-27.2646 -27.1367l27.2646 -27.1357l-27.2646 -27.1348l-27.1367 27.1348l-27.1357 -27.1348l-27.1348 27.1348l27.1348 27.1357
l-27.1348 27.1367l27.1348 27.2646l27.1357 -27.2646zM255.872 448c141.439 0 256.128 -114.561 256.128 -255.999c0 -141.439 -114.688 -256 -256.128 -256s-255.872 114.561 -255.872 256c0 141.438 114.432 255.999 255.872 255.999zM255.999 -12.7998
c113.153 0 204.801 91.6484 204.801 204.801c0 113.151 -91.6484 204.799 -204.801 204.799c-113.151 0 -204.8 -91.6465 -204.8 -204.799c0 -113.153 91.6484 -204.801 204.8 -204.801z" />
<glyph glyph-name="uniF102" unicode="&#xf102;"
d="M255.744 448c141.567 0 256.256 -114.688 256.256 -255.999c0 -141.312 -114.688 -256 -256.256 -256c-141.312 0 -255.744 114.688 -255.744 256c0 141.312 114.432 255.999 255.744 255.999zM255.999 -12.7998c113.153 0 204.801 91.6484 204.801 204.801
c0 113.151 -91.6484 204.799 -204.801 204.799c-113.151 0 -204.8 -91.6465 -204.8 -204.799c0 -113.153 91.6484 -204.801 204.8 -204.801zM179.199 102.4v38.3994h153.601v-38.3994h-153.601zM204.8 256c0 -21.248 -17.1514 -38.3994 -38.3994 -38.3994
s-38.4004 17.1514 -38.4004 38.3994s17.1523 38.4004 38.4004 38.4004s38.3994 -17.1523 38.3994 -38.4004zM345.6 294.4c21.248 0 38.4004 -17.1523 38.4004 -38.4004s-17.1523 -38.3994 -38.4004 -38.3994s-38.3994 17.1514 -38.3994 38.3994
s17.1514 38.4004 38.3994 38.4004z" />
<glyph glyph-name="uniF105" unicode="&#xf105;"
d="M166.4 217.601c-21.248 0 -38.4004 17.1514 -38.4004 38.3994s17.1523 38.4004 38.4004 38.4004s38.3994 -17.1523 38.3994 -38.4004s-17.1514 -38.3994 -38.3994 -38.3994zM345.6 217.601c-21.248 0 -38.3994 17.1514 -38.3994 38.3994s17.1514 38.4004 38.3994 38.4004
s38.4004 -17.1523 38.4004 -38.4004s-17.1523 -38.3994 -38.4004 -38.3994zM255.999 89.5996c37.7607 0 70.4004 20.7363 88.1943 51.2002h42.8799c-20.4805 -52.3516 -71.4238 -89.5996 -131.072 -89.5996s-110.593 37.248 -131.072 89.5996h42.8789
c17.791 -30.4639 50.4316 -51.2002 88.1914 -51.2002zM255.744 448c141.567 0 256.256 -114.688 256.256 -255.999c0 -141.312 -114.688 -256 -256.256 -256c-141.312 0 -255.744 114.688 -255.744 256c0 141.312 114.432 255.999 255.744 255.999zM255.999 -12.7998
c113.153 0 204.801 91.6484 204.801 204.801c0 113.151 -91.6484 204.799 -204.801 204.799c-113.151 0 -204.8 -91.6465 -204.8 -204.799c0 -113.153 91.6484 -204.801 204.8 -204.801z" />
<glyph glyph-name="uniF103" unicode="&#xf103;"
d="M345.6 217.601c-21.248 0 -38.3994 17.1514 -38.3994 38.3994s17.1514 38.4004 38.3994 38.4004s38.4004 -17.1523 38.4004 -38.4004s-17.1523 -38.3994 -38.4004 -38.3994zM255.872 448c141.439 0 256.128 -114.561 256.128 -255.999
c0 -141.439 -114.688 -256 -256.128 -256s-255.872 114.561 -255.872 256c0 141.438 114.432 255.999 255.872 255.999zM255.999 -12.7998c113.153 0 204.801 91.6484 204.801 204.801c0 113.151 -91.6484 204.799 -204.801 204.799
c-113.151 0 -204.8 -91.6465 -204.8 -204.799c0 -113.153 91.6484 -204.801 204.8 -204.801zM166.4 217.601c-21.248 0 -38.4004 17.1514 -38.4004 38.3994s17.1523 38.4004 38.4004 38.4004s38.3994 -17.1523 38.3994 -38.4004s-17.1514 -38.3994 -38.3994 -38.3994z
M255.999 51.2002c-59.6465 0 -110.208 37.248 -130.687 89.5996h261.375c-20.4805 -52.3516 -71.04 -89.5996 -130.688 -89.5996z" />
</font>
</defs></svg>

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@@ -29,7 +29,7 @@ import * as circleActions from 'actions/circleActions'
import { ICircleComponentProps } from './ICircleComponentProps'
import { ICircleComponentState } from './ICircleComponentState'
import { Circle } from 'core/domain/circles'
import { Circle, UserTie } from 'core/domain/circles'
import { Profile } from 'core/domain/users/profile'
/**
@@ -135,21 +135,21 @@ export class CircleComponent extends Component<ICircleComponentProps, ICircleCom
}
userList = () => {
const { users } = this.props.circle
const { userInfo } = this.props
const { usersOfCircle } = this.props
let usersParsed: any = []
if (users) {
Object.keys(users).forEach((key, index) => {
const { fullName } = users[key]
let avatar = userInfo && userInfo[key] ? userInfo[key].avatar || '' : ''
if (usersOfCircle) {
console.trace('usersOfCircle',usersOfCircle)
Object.keys(usersOfCircle).forEach((userId, index) => {
const { fullName } = usersOfCircle[userId]
let avatar = usersOfCircle && usersOfCircle[userId] ? usersOfCircle[userId].avatar || '' : ''
usersParsed.push(<ListItem
key={`${this.props.id}.${key}`}
key={`${this.props.id}.${userId}`}
style={this.styles.userListItem as any}
value={2}
primaryText={fullName}
leftAvatar={<UserAvatar fullName={fullName} fileName={avatar as any} />}
onClick={() => this.props.goTo!(`/${key}`)}
leftAvatar={<UserAvatar fullName={fullName!} fileName={avatar} />}
onClick={() => this.props.goTo!(`/${userId}`)}
/>)
})
@@ -176,6 +176,7 @@ export class CircleComponent extends Component<ICircleComponentProps, ICircleCom
*/
render () {
const {circle} = this.props
const circleTitle = (
<div>
<div style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between' }}>
@@ -203,7 +204,7 @@ export class CircleComponent extends Component<ICircleComponentProps, ICircleCom
style={{ backgroundColor: '#fff', borderBottom: '1px solid rgba(0,0,0,0.12)', height: '72px', padding: '12px 0' }}
primaryText={<span style={{ color: 'rgba(0,0,0,0.87)', fontSize: '16px', marginRight: '8px', whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }}>{this.props.circle.name}</span>}
leftIcon={<SvgGroup style={{ width: '40px', height: '40px', transform: 'translate(0px, -9px)', fill: '#bdbdbd' }} />}
rightIconButton={this.rightIconMenu}
rightIconButton={!circle.isSystem ? this.rightIconMenu : null}
initiallyOpen={false}
onClick={this.handleToggleCircle}
open={this.state.open}
@@ -259,10 +260,23 @@ const mapDispatchToProps = (dispatch: any, ownProps: ICircleComponentProps) => {
*/
const mapStateToProps = (state: any, ownProps: ICircleComponentProps) => {
const {circle, authorize, server} = state
const {userTies} = circle
const { uid } = state.authorize
const circles: { [circleId: string]: Circle } = circle ? (circle.circleList || {}) : {}
const currentCircle = (circles ? circles[ownProps.id] : {}) as Circle
let usersOfCircle: {[userId: string]: UserTie} = {}
Object.keys(userTies).forEach((userTieId) => {
const theUserTie = userTies[userTieId] as UserTie
if (theUserTie.circleIdList!.indexOf(ownProps.id) > -1) {
usersOfCircle = {
...usersOfCircle,
[userTieId]: theUserTie
}
}
})
return {
usersOfCircle,
openSetting: state.circle ? (currentCircle ? (currentCircle.openCircleSettings || false) : false) : false,
userInfo: state.user.info

View File

@@ -1,6 +1,6 @@
import { Comment } from 'core/domain/comments'
import { Profile } from 'core/domain/users'
import { Circle } from 'core/domain/circles'
import { Circle, UserTie } from 'core/domain/circles'
export interface ICircleComponentProps {
@@ -45,12 +45,9 @@ export interface ICircleComponentProps {
deleteCircle?: Function
/**
* Users profile
*
* @type {{[userId: string]: Profile}}
* @memberof ICircleComponentProps
* Users of current circle
*/
userInfo?: {[userId: string]: Profile}
usersOfCircle?: {[userId: string]: UserTie}
/**
* Close setting box of circle

View File

@@ -20,6 +20,6 @@ export interface IFindPeopleComponentProps {
/**
* If there are more people {true} or not {false}
*/
hasMorePeople: boolean
hasMorePeople?: boolean
}

View File

@@ -83,8 +83,9 @@ const mapStateToProps = (state: any,ownProps: IFollowersComponentProps) => {
const {circle, authorize, server} = state
const { uid } = state.authorize
const circles: { [circleId: string]: Circle } = circle ? (circle.circleList || {}) : {}
const followers = circle ? circle.userTieds : {}
return{
followers: circles ? circles.userTieds : {}
followers
}
}

View File

@@ -6,11 +6,11 @@ import PropTypes from 'prop-types'
// - Import app components
import UserBoxList from 'components/userBoxList'
import { Circle } from 'core/domain/circles'
// - Import API
import CircleAPI from 'api/CircleAPI'
import { IFollowingComponentProps } from './IFollowingComponentProps'
import { IFollowingComponentState } from './IFollowingComponentState'
import { Circle } from 'core/domain/circles';
// - Import actions

View File

@@ -26,7 +26,6 @@ import PostPage from 'components/postPage'
import People from 'components/people'
// - Import API
import CircleAPI from 'api/CircleAPI'
// - Import actions
// - Import actions
@@ -130,7 +129,7 @@ export class HomeComponent extends Component<IHomeComponentProps, IHomeComponent
* @memberof Home
*/
render () {
const {loaded, authed, loadDataStream, mergedPosts, hasMorePosts} = this.props
const {loaded, authed, loadDataStream, mergedPosts, hasMorePosts, showSendFeedback} = this.props
return (
<div id='home'>
<HomeHeader sidebar={this.state.sidebarOpen} sidebarStatus={this.state.sidebarStatus} />
@@ -147,7 +146,7 @@ export class HomeComponent extends Component<IHomeComponentProps, IHomeComponent
<NavLink to='/people'><MenuItem primaryText='People' style={{ color: 'rgb(117, 117, 117)' }} leftIcon={<SvgPeople />} /></NavLink>
<Divider />
<NavLink to='/settings'><MenuItem primaryText='Settings' style={{ color: 'rgb(117, 117, 117)' }} leftIcon={<SvgSettings />} /></NavLink>
<NavLink to='#'><MenuItem primaryText='Send feedback' style={{ color: 'rgb(117, 117, 117)' }} leftIcon={<SvgFeedback />} /></NavLink>
<MenuItem primaryText='Send feedback' onClick={() => showSendFeedback()} style={{ color: 'rgb(117, 117, 117)' }} leftIcon={<SvgFeedback />} />
</Menu>
</SidebarContent>
@@ -175,6 +174,7 @@ const mapDispatchToProps = (dispatch: any, ownProps: IHomeComponentProps) => {
dispatch(notifyActions.dbGetNotifications())
dispatch(circleActions.dbGetCircles())
dispatch(circleActions.dbGetUserTies())
dispatch(circleActions.dbGetFollowers())
},
clearData: () => {
@@ -192,7 +192,10 @@ const mapDispatchToProps = (dispatch: any, ownProps: IHomeComponentProps) => {
defaultDataEnable: () => {
dispatch(globalActions.defaultDataEnable())
},
goTo: (url: string) => dispatch(push(url))
goTo: (url: string) => dispatch(push(url)),
showSendFeedback: () => dispatch(globalActions.showSendFeedback()),
hideSendFeedback: () => dispatch(globalActions.hideSendFeedback())
}
}
@@ -223,7 +226,7 @@ const mapStateToProps = (state: any, ownProps: IHomeComponentProps) => {
mergedPosts,
global,
hasMorePosts,
loaded: user.loaded && post.loaded && imageGallery.loaded && notify.loaded && circle.loaded
loaded: user.loaded && imageGallery.loaded && notify.loaded && circle.loaded
}
}

View File

@@ -98,4 +98,14 @@ export interface IHomeComponentProps {
*/
loaded?: boolean
/**
* Show send feedback form
*/
showSendFeedback: () => any
/**
* Hide send feedback form
*/
hideSendFeedback: () => any
}

View File

@@ -1,4 +1,4 @@
import { User } from 'core/domain/users';
import { User } from 'core/domain/users'
export interface IMasterComponentProps {
/**
* Close gloal message
@@ -98,4 +98,15 @@ export interface IMasterComponentProps {
* @memberof IMasterProps
*/
uid: string
/**
* Show master loading
*/
showMasterLoading?: () => any
/**
* Hide master loading
*/
hideMasterLoading?: () => any
}

View File

@@ -10,6 +10,7 @@ import LinearProgress from 'material-ui/LinearProgress'
// - Import components
import MasterLoading from 'components/masterLoading'
import SendFeedback from 'components/sendFeedback'
import MasterRouter from 'routes/MasterRouter'
import { IMasterComponentProps } from './IMasterComponentProps'
import { IMasterComponentState } from './IMasterComponentState'
@@ -79,9 +80,20 @@ export class MasterComponent extends Component<IMasterComponentProps, IMasterCom
componentDidMount () {
this._authourizeService.onAuthStateChanged((isVerifide: boolean, user: any) => {
const {global, clearData, loadDataGuest, defaultDataDisable, defaultDataEnable, login, logout } = this.props
const {
global,
clearData,
loadDataGuest,
defaultDataDisable,
defaultDataEnable,
login,
logout,
showMasterLoading,
hideMasterLoading
} = this.props
if (user) {
login(user.uid,isVerifide)
hideMasterLoading!()
this.setState({
loading: false,
isVerifide: true
@@ -89,6 +101,7 @@ export class MasterComponent extends Component<IMasterComponentProps, IMasterCom
} else {
logout()
hideMasterLoading!()
this.setState({
loading: false,
isVerifide: false
@@ -117,14 +130,14 @@ export class MasterComponent extends Component<IMasterComponentProps, IMasterCom
return (
<div id='master'>
<SendFeedback />
<div className='master__progress' style={{ display: (progress.visible ? 'block' : 'none') }}>
<LinearProgress mode='determinate' value={progress.percent} />
</div>
<div className='master__loading animate-fading2' style={{ display: (global.showTopLoading ? 'flex' : 'none') }}>
<div className='title'>Loading ... </div>
</div>
<MasterLoading activeLoading={loading} handleLoading={this.handleLoading} />
<MasterLoading activeLoading={global.showMasterLoading} handleLoading={this.handleLoading} />
<MasterRouter enabled={!loading} data={{uid}} />
<Snackbar
open={this.props.global.messageOpen}
@@ -170,7 +183,9 @@ const mapDispatchToProps = (dispatch: any, ownProps: IMasterComponentProps) => {
},
loadDataGuest: () => {
dispatch(globalActions.loadDataGuest())
}
},
showMasterLoading: () => dispatch(globalActions.showMasterLoading()),
hideMasterLoading: () => dispatch(globalActions.hideMasterLoading())
}
}

View File

@@ -2,13 +2,14 @@
import React, { Component } from 'react'
import CircularProgress from 'material-ui/CircularProgress'
import Dialog from 'material-ui/Dialog'
import RefreshIndicator from 'material-ui/RefreshIndicator'
import { IMasterLoadingComponentProps } from './IMasterLoadingComponentProps'
import { IMasterLoadingComponentState } from './IMasterLoadingComponentState'
// - Import app components
// - Create MasterLoading component class
export default class MasterLoadingComponent extends Component<IMasterLoadingComponentProps,IMasterLoadingComponentState> {
export default class MasterLoadingComponent extends Component<IMasterLoadingComponentProps, IMasterLoadingComponentState> {
// Constructor
constructor (props: IMasterLoadingComponentProps) {
@@ -19,27 +20,19 @@ export default class MasterLoadingComponent extends Component<IMasterLoadingComp
// Render app DOM component
render () {
const {activeLoading} = this.props
return (
<Dialog
modal={true}
open={this.props.activeLoading}
autoDetectWindowHeight={false}
overlayStyle={{backgroundColor: 'white'}}
contentClassName='mLoading__content'
bodyStyle={{backgroundColor: ''}}
bodyClassName='mLoading__body'
>
<div>
<div className='mLoading__context'>
<CircularProgress color='white' size={80} thickness={7} />
<h1 style={{float: 'right', color: '#fff'}}>Green</h1>
<div className='mLoading__loading' style={{ display: (activeLoading ? 'flex' : 'none') }}>
<RefreshIndicator
size={50}
left={70}
top={0}
status='loading'
/>
</div>
</div>
</Dialog>
)
}

View File

@@ -0,0 +1,30 @@
import { Feed } from 'core/domain/common/feed'
import { ServerRequestModel } from 'models/server/serverRequestModel'
import { Profile } from 'core/domain/users'
export interface ISendFeedbackComponentProps {
/**
* Whether send feedback is diplayed
*/
sendFeedbackStatus?: boolean
/**
* Send feedback
*/
sendFeed?: (feed: Feed) => any
/**
* Hide feedback form
*/
hideFeedback: () => any
/**
* The server request of send feedback
*/
sendFeedbackRequest: ServerRequestModel
/**
* Current user profile
*/
currentUser: Profile
}

View File

@@ -0,0 +1,7 @@
export interface ISendFeedbackComponentState {
/**
* Feedback text
*/
feedText: string
}

View File

@@ -0,0 +1,232 @@
// - Import react components
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import Paper from 'material-ui/Paper'
import TextField from 'material-ui/TextField'
import IconButton from 'material-ui/IconButton'
import SvgHappy from 'material-ui/svg-icons/image/tag-faces'
import SvgSad from 'material-ui/svg-icons/action/face'
import SvgClose from 'material-ui/svg-icons/content/clear'
import RefreshIndicator from 'material-ui/RefreshIndicator'
// - Import app components
// - Import API
// - Import actions
import { globalActions } from 'actions'
import { Feed } from 'core/domain/common'
import { ISendFeedbackComponentProps } from './ISendFeedbackComponentProps'
import { ISendFeedbackComponentState } from './ISendFeedbackComponentState'
import { FeedType } from 'core/domain/common/feedType'
import { ServerRequestModel } from 'models/server'
import { Profile } from 'core/domain/users'
import StringAPI from 'api/StringAPI'
import { ServerRequestType } from 'constants/serverRequestType'
import { User } from 'core/domain/users'
import { ServerRequestStatusType } from 'actions/serverRequestStatusType'
/**
* Create component class
*/
export class SendFeedbackComponent extends Component<ISendFeedbackComponentProps, ISendFeedbackComponentState> {
/**
* Component constructor
* @param {object} props is an object properties of component
*/
constructor(props: ISendFeedbackComponentProps) {
super(props)
// Defaul state
this.state = {
feedText: ''
}
// Binding functions to `this`
this.handleFeedText = this.handleFeedText.bind(this)
this.getFeedbackForm = this.getFeedbackForm.bind(this)
this.mainForm = this.mainForm.bind(this)
this.loadingForm = this.loadingForm.bind(this)
this.successForm = this.successForm.bind(this)
this.errorForm = this.errorForm.bind(this)
}
handleFeedText = (event: any) => {
const target = event ? event.target : {}
const value = target ? target.value : ''
if (value) {
this.setState({
feedText: value
})
}
}
handleSendFeed = (feedType: FeedType) => {
const { sendFeed, currentUser } = this.props
const { feedText } = this.state
sendFeed!(new Feed('', feedText, feedType, currentUser))
}
mainForm = () => {
const { sendFeedbackStatus, hideFeedback, sendFeed, sendFeedbackRequest } = this.props
const { feedText } = this.state
return (
<div>
<TextField
hintText='What do you feel?'
multiLine={true}
onChange={this.handleFeedText}
rows={2}
rowsMax={4}
/><br />
<div className='buttons'>
<IconButton
tooltip='sad'
iconClassName='flaticon-sad-2 icon__svg'
tooltipPosition='bottom-left'
onClick={() => this.handleSendFeed(FeedType.Sad)}
>
</IconButton>
<IconButton
tooltip='acceptable'
iconClassName='flaticon-neutral icon__svg'
tooltipPosition='bottom-left'
onClick={() => this.handleSendFeed(FeedType.Acceptable)}
>
</IconButton>
<IconButton
tooltip='happy'
iconClassName='flaticon-happy-2 icon__svg'
tooltipPosition='bottom-left'
onClick={() => this.handleSendFeed(FeedType.Happy)}
>
</IconButton>
<IconButton
tooltip='awesome'
iconClassName='flaticon-happy icon__svg'
tooltipPosition='bottom-left'
onClick={() => this.handleSendFeed(FeedType.Awesome)}
>
</IconButton>
</div>
</div >)
}
loadingForm = () => {
return (<div className='loading'>
<p>
Your feedback is sending!
</p>
<div className='icon'>
<RefreshIndicator
size={50}
left={70}
top={0}
status='loading'
/>
</div>
</div>)
}
successForm = () => {
return (<div className='success'>We appreciate your kind support as always ;)</div>)
}
errorForm = () => {
return (<div className='error'>Error in sending feedback :(</div>)
}
getFeedbackForm = () => {
const { sendFeedbackStatus, hideFeedback, sendFeed, sendFeedbackRequest } = this.props
const { feedText } = this.state
if (sendFeedbackRequest) {
switch (sendFeedbackRequest.status) {
case ServerRequestStatusType.Sent:
return this.loadingForm()
case ServerRequestStatusType.OK:
return this.successForm()
case ServerRequestStatusType.Error:
return this.errorForm()
default:
return this.mainForm()
}
} else {
return this.mainForm()
}
}
/**
* Reneder component DOM
* @return {react element} return the DOM which rendered by component
*/
render() {
const { sendFeedbackStatus, hideFeedback, sendFeed, sendFeedbackRequest } = this.props
const { feedText } = this.state
return (
<div className='sendFeedback__content animate__up' style={{ display: (sendFeedbackStatus ? 'block' : 'none') }}>
<Paper className='paper' >
<div className='close'>
<IconButton
tooltip='cancel'
tooltipPosition='bottom-left'
onClick={() => hideFeedback()}
>
<SvgClose />
</IconButton>
</div>
{this.getFeedbackForm()}
</Paper>
</div>
)
}
}
/**
* Map dispatch to props
* @param {func} dispatch is the function to dispatch action to reducers
* @param {object} ownProps is the props belong to component
* @return {object} props of component
*/
const mapDispatchToProps = (dispatch: Function, ownProps: ISendFeedbackComponentProps) => {
return {
sendFeed: (feed: Feed) => (dispatch(globalActions.dbSendFeed(feed))),
hideFeedback: () => dispatch(globalActions.hideSendFeedback())
}
}
/**
* Map state to props
* @param {object} state is the obeject from redux store
* @param {object} ownProps is the props belong to component
* @return {object} props of component
*/
const mapStateToProps = (state: any, ownProps: ISendFeedbackComponentProps) => {
const { server, global, authorize, user } = state
const { request } = server
const { uid } = authorize
const currentUser: User = user.info && user.info[uid] ? { ...user.info[uid], userId: uid } : {}
const { sendFeedbackStatus } = global
const sendFeedbackRequest: ServerRequestModel = request ? request[StringAPI.createServerRequestId(ServerRequestType.CommonSendFeedback, uid)] : null
return {
sendFeedbackStatus,
sendFeedbackRequest,
currentUser
}
}
// - Connect component to redux store
export default connect(mapStateToProps, mapDispatchToProps)(SendFeedbackComponent as any)

View File

@@ -0,0 +1,2 @@
import SendFeedbackComponent from './SendFeedbackComponent'
export default SendFeedbackComponent

View File

@@ -281,4 +281,4 @@ const mapStateToProps = (state: any,ownProps: ISignupComponentProps) => {
}
// - Connect component to redux store
export default withRouter(connect(mapStateToProps,mapDispatchToProps)(SignupComponent as any))
export default withRouter(connect(mapStateToProps,mapDispatchToProps)(SignupComponent as any) as any)

View File

@@ -1,6 +1,8 @@
import { User } from 'core/domain/users'
import { Circle } from 'core/domain/circles/circle'
import { UserTie } from 'core/domain/circles'
import { ServerRequestStatusType } from 'actions/serverRequestStatusType'
import { ServerRequestModel } from 'models/server/serverRequestModel'
export interface IUserBoxComponentProps {
@@ -73,6 +75,11 @@ export interface IUserBoxComponentProps {
*/
fullName?: string
/**
* The `Following` circle identifier of current user
*/
followingCircleId?: string
/**
* Create a circle
*
@@ -85,14 +92,37 @@ export interface IUserBoxComponentProps {
*
* @memberof IUserBoxComponentProps
*/
addFollowingUser?: (cid: string,user: UserTie) => any
addUserToCircle?: (circleIds: string[],user: UserTie) => any
/**
* Delete
*
* @memberof IUserBoxComponentProps
* Add referer user to the `Following` circle of current user
*/
deleteFollowingUser?: (cid: string ,followingId: string) => any
followUser?: (circleId: string, userFollowing: UserTie) => any
/**
* Delete following user
*/
deleteFollowingUser?: (followingId: string) => any
/**
* Set current user selected circles for referer user
*/
setSelectedCircles?: (userId: string, circleList: string[]) => any
/**
* Remove current user selected circles for referer user
*/
removeSelectedCircles?: (userId: string, circleList: string[]) => any
/**
* Open select circle box
*/
openSelectCircles?: (userId: string) => any
/**
* Close select circle box
*/
closeSelectCircles?: (userId: string) => any
/**
* Redirect page to [url]
@@ -100,4 +130,29 @@ export interface IUserBoxComponentProps {
* @memberof IUserBoxComponentProps
*/
goTo?: (url: string) => any
/**
* The status of following user server request
*/
followRequest?: ServerRequestModel
/**
* The status of add to circle user server request
*/
addToCircleRequest?: ServerRequestModel
/**
* The status of deleting following user server request
*/
deleteFollowingUserRequest?: ServerRequestModel
/**
* Keep selected circles for refere user
*/
selectedCircles?: string[]
/**
* Whether the select circles box for referer user is open
*/
isSelecteCirclesOpen?: boolean
}

View File

@@ -33,22 +33,10 @@ export interface IUserBoxComponentState {
*/
anchorEl?: any
/**
* Circle list popover is open {true} or not {false}
*
* @type {boolean}
* @memberof IUserBoxComponentState
*/
open: boolean
/**
* Whether current user changed the selected circles for referer user
*
*/
disabledDoneCircles: boolean
/**
* Keep selected circles for refere user
*/
selectedCircles: string[]
}

View File

@@ -1,5 +1,6 @@
// - Import react components
import React, { Component } from 'react'
import moment from 'moment'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import { push } from 'react-router-redux'
@@ -20,7 +21,6 @@ import { grey400, grey800, darkBlack, lightBlack } from 'material-ui/styles/colo
import UserAvatar from 'components/userAvatar'
// - Import API
import CircleAPI from 'api/CircleAPI'
import StringAPI from 'api/StringAPI'
// - Import actions
@@ -31,12 +31,16 @@ import { IUserBoxComponentState } from './IUserBoxComponentState'
import { User } from 'core/domain/users'
import { UserTie, Circle } from 'core/domain/circles'
import { ServerRequestType } from 'constants/serverRequestType'
import { ServerRequestStatusType } from 'actions/serverRequestStatusType'
import { ServerRequestModel } from 'models/server'
/**
* Create component class
*/
export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBoxComponentState> {
/**
* Fields
*/
static propTypes = {
/**
* User identifier
@@ -69,6 +73,7 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
borderRadius: '4px'
}
}
selectedCircles: string[]
/**
* Component constructor
@@ -76,17 +81,13 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
*/
constructor (props: IUserBoxComponentProps) {
super(props)
const { userBelongCircles, circles } = this.props
const { userBelongCircles, circles,userId } = this.props
// Defaul state
this.state = {
/**
* It will be true if user follow popover is open
*/
open: false,
/**
* The value of circle input
*/
circleName: '',
circleName: ``,
/**
* It will be true if the text field for adding group is empty
*/
@@ -95,34 +96,52 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
* 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
}
this.selectedCircles = userBelongCircles!.slice()
// Binding functions to `this`
this.handleChangeName = this.handleChangeName.bind(this)
this.onCreateCircle = this.onCreateCircle.bind(this)
this.handleFollowUser = this.handleFollowUser.bind(this)
this.handleFollowUser = this.handleFollowUser.bind(this)
this.handleDoneAddCircle = this.handleDoneAddCircle.bind(this)
this.circleList = this.circleList.bind(this)
}
/**
* Handle follow user
*/
handleFollowUser = (checked: boolean, cid: string) => {
const { userId, user } = this.props
handleDoneAddCircle = () => {
const { userId, user , addUserToCircle, selectedCircles, deleteFollowingUser} = this.props
const { avatar, fullName } = user
if (checked) {
this.props.addFollowingUser!(cid, { avatar, userId, fullName })
const {disabledDoneCircles} = this.state
if (!disabledDoneCircles) {
if (selectedCircles!.length > 0) {
addUserToCircle!(selectedCircles!, { avatar, userId, fullName })
} else {
deleteFollowingUser!(userId)
}
}
}
/**
* Handle follow user
*/
onFollowUser = (event: any) => {
// This prevents ghost click
event.preventDefault()
const {isFollowed, followUser, followingCircleId, userId, user, followRequest } = this.props
if (followRequest && followRequest.status === ServerRequestStatusType.Sent) {
return
}
const { avatar, fullName } = user
if (!isFollowed) {
followUser!(followingCircleId!, { avatar, userId, fullName })
} else {
this.props.deleteFollowingUser!(cid, userId)
this.onRequestOpenAddCircle()
}
}
@@ -130,8 +149,14 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
* Handle request close for add circle box
*/
onRequestCloseAddCircle = () => {
const {setSelectedCircles, userId, userBelongCircles, closeSelectCircles} = this.props
setSelectedCircles!(userId, userBelongCircles!)
closeSelectCircles!(userId)
this.setState({
open: false
circleName: ``,
disabledCreateCircle: true,
disabledAddToCircle: true,
disabledDoneCircles: true
})
}
@@ -139,9 +164,8 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
* Handle request open for add circle box
*/
onRequestOpenAddCircle = () => {
this.setState({
open: true
})
const { openSelectCircles, userId} = this.props
openSelectCircles!(userId)
}
/**
@@ -170,54 +194,40 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
}
handleSelectCircle = (event: object, isInputChecked: boolean, circleId: string) => {
const { userBelongCircles, circles } = this.props
let selectedCircles = this.state.selectedCircles
const { userBelongCircles, circles, setSelectedCircles, selectedCircles, userId } = this.props
let newSelectedCircles = selectedCircles!.slice()
if (isInputChecked) {
selectedCircles = [
...selectedCircles,
newSelectedCircles = [
...selectedCircles!,
circleId
]
} else {
const circleIndex = selectedCircles.indexOf(circleId)
selectedCircles.splice(circleIndex, 1)
const circleIndex = selectedCircles!.indexOf(circleId)
newSelectedCircles.splice(circleIndex, 1)
}
setSelectedCircles!(userId, newSelectedCircles)
this.setState({
selectedCircles: selectedCircles,
disabledDoneCircles: !this.selectedCircleChange(selectedCircles)
disabledDoneCircles: !this.selectedCircleChange(newSelectedCircles)
})
}
/**
* Handle follow user
*/
onFollowUser = (event: any) => {
// This prevents ghost click
event.preventDefault()
this.onRequestOpenAddCircle()
}
/**
* Add user to the circle/circles
*/
onAddToCircle = () => {
}
/**
* Create a circle list of user which belong to
*/
circleList = () => {
let { circles, userId, userBelongCircles } = this.props
let { circles, userId, userBelongCircles, selectedCircles } = this.props
if (circles) {
return Object.keys(circles).map((circleId, index) => {
const {selectedCircles} = this.state
let isBelong = selectedCircles!.indexOf(circleId) > -1
const parsedDate = Object.keys(circles).map((circleId, index) => {
let isBelong = selectedCircles ? selectedCircles!.indexOf(circleId) > -1 : false
// Create checkbox for selected/unselected circle
return <Checkbox
key={circleId}
key={`${circleId}-${userId}`}
style={{ padding: '10px' }}
label={circles![circleId].name}
labelStyle={{
@@ -230,6 +240,8 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
checked={isBelong}
/>
})
return parsedDate
}
}
@@ -260,6 +272,7 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
*/
render () {
const {disabledDoneCircles} = this.state
const { isFollowed, followRequest, userId, isSelecteCirclesOpen, addToCircleRequest, deleteFollowingUserRequest } = this.props
const writeActions = [
<FlatButton
label='Cancel'
@@ -272,15 +285,14 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
label='Done'
primary={true}
keyboardFocused={false}
disabled={disabledDoneCircles}
onTouchTap={this.onCreateCircle}
disabled={disabledDoneCircles || (addToCircleRequest ? addToCircleRequest!.status === ServerRequestStatusType.Sent : false)}
onTouchTap={this.handleDoneAddCircle}
/>
]
const { isFollowed } = this.props
return (
<Paper style={this.styles.paper} zDepth={1} className='grid-cell'>
<Paper key={userId} style={this.styles.paper} zDepth={1} className='grid-cell'>
<div style={{
display: 'flex',
flexDirection: 'column',
@@ -309,6 +321,10 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
: (this.props.belongCirclesCount! > 1 ? `${this.props.belongCirclesCount} Circles` : ((this.props.firstBelongCircle) ? this.props.firstBelongCircle.name : 'Follow'))}
primary={true}
onTouchTap={this.onFollowUser}
disabled={
(followRequest ? followRequest.status === ServerRequestStatusType.Sent : false) ||
(deleteFollowingUserRequest ? deleteFollowingUserRequest.status === ServerRequestStatusType.Sent : false)
}
/>
</div>
</div>
@@ -316,7 +332,7 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
key={this.props.userId || 0}
actions={writeActions}
modal={false}
open={this.state.open}
open={isSelecteCirclesOpen === true}
contentStyle={this.styles.dialog}
onRequestClose={this.onRequestCloseAddCircle}
overlayStyle={{ background: 'rgba(0,0,0,0.12)' }}
@@ -363,8 +379,13 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
const mapDispatchToProps = (dispatch: Function, ownProps: IUserBoxComponentProps) => {
return {
createCircle: (name: string) => dispatch(circleActions.dbAddCircle(name)),
addFollowingUser: (circleIds: string[], user: UserTie) => dispatch(circleActions.dbUpdateUserInCircles(circleIds, user)),
deleteFollowingUser: (cid: string, followingId: string) => dispatch(circleActions.dbDeleteFollowingUser(followingId)),
addUserToCircle: (circleIds: string[], user: UserTie) => dispatch(circleActions.dbUpdateUserInCircles(circleIds, user)),
followUser: (circleId: string, userFollowing: UserTie) => dispatch(circleActions.dbFollowUser(circleId, userFollowing)),
deleteFollowingUser: (followingId: string) => dispatch(circleActions.dbDeleteFollowingUser(followingId)),
setSelectedCircles: (userId: string, circleList: string[]) => dispatch(circleActions.setSelectedCircles(userId, circleList)),
removeSelectedCircles: (userId: string, circleList: string[]) => dispatch(circleActions.removeSelectedCircles(userId)),
openSelectCircles: (userId: string) => dispatch(circleActions.openSelectCircleBox(userId)),
closeSelectCircles: (userId: string) => dispatch(circleActions.closeSelectCircleBox(userId)),
goTo: (url: string) => dispatch(push(url))
}
@@ -381,13 +402,26 @@ const mapStateToProps = (state: any, ownProps: IUserBoxComponentProps) => {
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
const followingCircleId = circles ? Object.keys(circles)
.filter((circleId) => circles[circleId].isSystem && circles[circleId].name === `Following`)[0] : ''
const followRequest: ServerRequestModel = request ? request[StringAPI.createServerRequestId(ServerRequestType.CircleFollowUser, ownProps.userId)] : null
const addToCircleRequest: ServerRequestModel = request ? request[StringAPI.createServerRequestId(ServerRequestType.CircleAddToCircle, ownProps.userId)] : null
const deleteFollowingUserRequest: ServerRequestModel = request ? request[StringAPI.createServerRequestId(ServerRequestType.CircleDeleteFollowingUser, ownProps.userId)] : null
const selectedCircles = circle.selectedCircles ? circle.selectedCircles[ownProps.userId] : []
const isSelecteCirclesOpen = circle.openSelecteCircles ? circle.openSelecteCircles[ownProps.userId] : []
return {
isSelecteCirclesOpen,
isFollowed,
selectedCircles,
circles,
followingCircleId,
userBelongCircles,
followRequest,
belongCirclesCount: userBelongCircles.length || 0,
firstBelongCircle: userBelongCircles ? (circles ? circles[userBelongCircles[0]] : {}) : {},
avatar: state.user.info && state.user.info[ownProps.userId] ? state.user.info[ownProps.userId].avatar || '' : '',

View File

@@ -45,9 +45,7 @@ export class YourCirclesComponent extends Component<IYourCirclesComponentProps,I
if (circles) {
Object.keys(circles).map((key, index) => {
if (key.trim() !== '-Followers') {
parsedCircles.push(<CircleComponent key={key} circle={circles![key]} id={key} uid={uid!} />)
}
})
}
return parsedCircles

View File

@@ -15,6 +15,10 @@ export enum CircleActionType {
DELETE_USER_FROM_CIRCLE = 'DELETE_USER_FROM_CIRCLE',
SHOW_SELECT_CIRCLE_BOX = 'SHOW_SELECT_CIRCLE_BOX',
HIDE_SELECT_CIRCLE_BOX = 'HIDE_SELECT_CIRCLE_BOX',
SET_SELECTED_CIRCLES_USER_BOX_COMPONENT = 'SET_SELECTED_CIRCLES_USER_BOX_COMPONENT',
REMOVE_SELECTED_CIRCLES_USER_BOX_COMPONENT = 'REMOVE_SELECTED_CIRCLES_USER_BOX_COMPONENT',
OPEN_SELECT_CIRCLES_USER_BOX_COMPONENT = 'OPEN_SELECT_CIRCLES_USER_BOX_COMPONENT',
CLOSE_SELECT_CIRCLES_USER_BOX_COMPONENT = 'CLOSE_SELECT_CIRCLES_USER_BOX_COMPONENT',
SHOW_FOLLOWING_USER_LOADING = 'SHOW_FOLLOWING_USER_LOADING',
HIDE_FOLLOWING_USER_LOADING = 'HIDE_FOLLOWING_USER_LOADING'

View File

@@ -12,6 +12,10 @@ export enum GlobalActionType {
SET_HEADER_TITLE = 'SET_HEADER_TITLE',
SHOW_TOP_LOADING = 'SHOW_TOP_LOADING',
HIDE_TOP_LOADING = 'HIDE_TOP_LOADING',
SHOW_MASTER_LOADING = 'SHOW_MASTER_LOADING',
HIDE_MASTER_LOADING = 'HIDE_MASTER_LOADING',
SHOW_SEND_FEEDBACK = 'SHOW_SEND_FEEDBACK',
HIDE_SEND_FEEDBACK = 'HIDE_SEND_FEEDBACK',
TEMP = 'TEMP',
CLEAR_TEMP = 'CLEAR_TEMP',
OPEN_POST_WRITE = 'OPEN_POST_WRITE',

View File

@@ -1,6 +1,8 @@
export enum ServerRequestType {
CircleAddToCircle = 'CircleAddToCircle',
CircleFollowUser = 'CircleFollowUser',
CircleCreateTieUser = 'CircleCreateTieUser'
CircleCreateTieUser = 'CircleCreateTieUser',
CircleDeleteFollowingUser = 'CircleDeleteFollowingUser',
CommonSendFeedback = 'CommonSendFeedback'
}

View File

@@ -35,8 +35,8 @@ export class Circle extends BaseDomain {
public name: string
/**
* Whether circle setting is open
* Whether it's configured by system
*/
public openCircleSettings?: boolean
public isSystem: boolean
}

View File

@@ -0,0 +1,34 @@
import { BaseDomain } from 'core/domain/common'
import { FeedType } from './feedType'
import { User } from 'core/domain/users'
export class Feed {
/**
* Constructor
*/
constructor (
/**
* Feed identifier
*/
public id?: string,
/**
* Feed text
*/
public text?: string,
/**
* Feed type
*/
public feedType?: FeedType,
/**
* The user who send the feedback
*/
public user?: User
) {
}
}

View File

@@ -0,0 +1,8 @@
export enum FeedType {
Awesome = 'Awesome',
Happy = 'Happey',
Acceptable = 'Acceptable',
Sad = 'Sad',
Bug = 'Bug'
}

View File

@@ -1,7 +1,9 @@
import { SocialError } from './socialError'
import { BaseDomain } from './baseDomain'
import { Feed } from './feed'
export {
SocialError,
BaseDomain
}
BaseDomain,
Feed
}

View File

@@ -15,6 +15,12 @@ export interface IUserTieService {
tieUseres: (userTieSenderInfo: UserTie, userTieReceiveInfo: UserTie, circleIds: string[])
=> Promise<void>
/**
* Update users tie
*/
updateUsersTie: (userTieSenderInfo: UserTie, userTieReceiveInfo: UserTie, circleIds: string[])
=> Promise<void>
/**
* Remove users' tie
*/

View File

@@ -1,4 +1,5 @@
import { User } from 'core/domain/users'
import { Feed } from 'core/domain/common';
/**
* Common service interface
@@ -8,4 +9,8 @@ import { User } from 'core/domain/users'
*/
export interface ICommonService {
/**
* Post feedback
*/
addFeed: (feed: Feed) => Promise<string>
}

View File

@@ -53,6 +53,32 @@ export class UserTieService implements IUserTieService {
})
}
/**
* Update users tie
*/
public updateUsersTie: (userTieSenderInfo: UserTie, userTieReceiveInfo: UserTie, circleIds: string[])
=> Promise<void> = (userTieSenderInfo, userTieReceiveInfo, circleIds) => {
return new Promise<void>((resolve, reject) => {
this._graphService
.updateGraph(
new Graph(
userTieSenderInfo.userId!,
'TIE',
userTieReceiveInfo.userId!,
{...userTieSenderInfo},
{...userTieReceiveInfo},
{creationDate: Date.now(), circleIds}
)
,'users'
).then(() => {
resolve()
})
.catch((error: any) => reject(new SocialError(error.code, 'firestore/updateUsersTie :' + error.message)))
})
}
/**
* Remove users' tie
*/
@@ -89,7 +115,7 @@ export class UserTieService implements IUserTieService {
parsedData = {
...parsedData,
[rightUserInfo.userId!] : {
...node.rightMetadata,
...rightUserInfo,
circleIdList: metadata ? metadata.circleIds : []
}
}
@@ -123,7 +149,7 @@ export class UserTieService implements IUserTieService {
parsedData = {
...parsedData,
[leftUserInfo.userId!] : {
...parsedData[leftUserInfo.userId!],
...leftUserInfo,
circleIdList: []
}
}

View File

@@ -1,7 +1,7 @@
// - Import react components
import { firebaseRef, firebaseAuth } from 'data/firebaseClient'
import { firebaseRef, firebaseAuth, db } from 'data/firestoreClient'
import { SocialError } from 'core/domain/common'
import { SocialError, Feed } from 'core/domain/common'
import { ICommonService } from 'core/services/common'
import { injectable } from 'inversify'
@@ -15,4 +15,20 @@ import { injectable } from 'inversify'
@injectable()
export class CommonService implements ICommonService {
/**
* Post feedback
*/
public addFeed: (feed: Feed)
=> Promise<string> = (feed) => {
return new Promise<string>((resolve, reject) => {
let feedRef = db.collection(`feeds`).doc()
feedRef.set({ ...feed, id: feedRef.id })
.then(() => {
resolve(feedRef.id)
})
.catch((error: any) => {
reject(new SocialError(error.code, error.message))
})
})
}
}

View File

@@ -34,17 +34,19 @@ export class GraphService implements IGraphService {
}
/**
* Add graph
* Update graph
*/
public updateGraph: (graph: Graph, collection: string)
=> Promise<string> = (graph, collection) => {
return new Promise<string>((resolve,reject) => {
let graphRef = db.collection(`graphs:${collection}`).doc()
.set({...graph}).then((result) => {
resolve()
})
.catch((error: any) => {
const graphData = this.getGraphs(collection, graph.leftNode, graph.edgeType, graph.rightNode)
.then((result) => {
graph.nodeId = result[0].nodeId
let graphRef = db.collection(`graphs:${collection}`).doc(result[0].nodeId)
.set({...graph}).then((result) => {
resolve()
})
}).catch((error: any) => {
reject(new SocialError(error.code,error.message))
})
})
@@ -114,19 +116,22 @@ export class GraphService implements IGraphService {
=> Promise<firebase.firestore.QuerySnapshot> = (collection, leftNode, edgeType, rightNode) => {
return new Promise<firebase.firestore.QuerySnapshot>((resolve,reject) => {
let graphsRef = db.collection(`graphs:${collection}`)
let query
if (leftNode) {
query = graphsRef.where('leftNode', '==', leftNode)
if (leftNode != null) {
graphsRef = graphsRef.where('leftNode', '==', leftNode)
}
if (rightNode && rightNode != null) {
query = graphsRef.where('rightNode', '==', rightNode)
console.trace('getGraphsQuery', {collection, leftNode, edgeType, rightNode})
graphsRef = graphsRef.where('rightNode', '==', rightNode)
}
if (edgeType) {
query = graphsRef.where('edgeType', '==', edgeType)
graphsRef = graphsRef.where('edgeType', '==', edgeType)
}
if (query) {
query.get().then((result) => {
if (graphsRef) {
graphsRef.get().then((result) => {
resolve(result)
}).catch((error) => reject(error))
} else {

View File

@@ -195,7 +195,7 @@ export class PostService implements IPostService {
// a = current item in array
// b = next item in array
return b[bKey].creationDate! - a[aKey].creationDate!
});
})
if (lastPostId && lastPostId !== '') {
const lastPostIndex = sortedObjects.findIndex((arg) => {
return Object.keys(arg)[0] === lastPostId

View File

@@ -91,7 +91,7 @@ export class UserService implements IUserService {
}
]
});
})
resolve({ users: parsedData, newLastUserId })
})
.catch((error: any) => {
@@ -107,11 +107,15 @@ export class UserService implements IUserService {
return new Promise<UserProvider>((resolve,reject) => {
let userProviderRef = db.doc(`userProviderInfo/${userId}`)
userProviderRef.get().then((snapshot) => {
let userProvider: UserProvider = snapshot.data() as UserProvider || {}
resolve(userProvider)
if (snapshot.exists) {
let userProvider: UserProvider = snapshot.data() as UserProvider || {}
resolve(userProvider)
} else {
throw new SocialError(`firestore/getUserProviderData/notExist `, `document of userProviderRef is not exist `)
}
})
.catch((error: any) => {
reject(new SocialError(error.code, 'firestore/getUserProviderData' + error.message))
reject(new SocialError(error.code, 'firestore/getUserProviderData ' + error.message))
})
})

View File

@@ -7,39 +7,49 @@ import { Circle, UserTie } from 'core/domain/circles'
* @class CircleState
*/
export class CircleState {
/**
* The list of users belong to users circle
*
* @memberof CircleState
*/
userTies: {[userId: string]: UserTie }= {}
/**
* The list of users belong to users circle
*
* @memberof CircleState
*/
userTies: { [userId: string]: UserTie } = {}
/**
* The list of users belong to users circle
*
* @memberof CircleState
*/
userTieds: {[userId: string]: UserTie }= {}
/**
* The list of users belong to users circle
*
* @memberof CircleState
*/
userTieds: { [userId: string]: UserTie } = {}
/**
* The list of circle of current user
*/
circleList: {[circleId: string]: Circle}
circleList: { [circleId: string]: Circle }
/**
* Whether select circle box is open for the selected user
*/
selectCircleStatus: {[userId: string]: boolean}
selectCircleStatus: { [userId: string]: boolean }
/**
* Whether following loading is shown for the selected user
*/
followingLoadingStatus: {[userId: string]: boolean}
followingLoadingStatus: { [userId: string]: boolean }
/**
* If user circles are loaded {true} or not {false}
*
* @memberof CircleState
*/
/**
* Keep selected circles for refere user
*/
selectedCircles: { [userId: string]: string[] }
/**
* Whether the select circles box for referer user is open
*/
openSelecteCircles: { [userId: string]: boolean }
/**
* If user circles are loaded {true} or not {false}
*
* @memberof CircleState
*/
loaded: boolean = false
}

View File

@@ -75,9 +75,13 @@ export let circleReducer = (state: CircleState = new CircleState(), action: ICir
...state,
userTies: {
...state.userTies,
[payload.userTie.user.userId]: {
[payload.userTie.userId]: {
...payload.userTie
}
},
selectedCircles: {
...state.selectedCircles,
[payload.userTie.userId]: payload.userTie.circleIdList
}
}
@@ -98,7 +102,8 @@ export let circleReducer = (state: CircleState = new CircleState(), action: ICir
userTies: {
...state.userTies,
...payload.userTies
}
},
selectedCircles : getSelectedCircles(payload.userTies)
}
case CircleActionType.ADD_USER_TIED_LIST:
@@ -139,9 +144,9 @@ export let circleReducer = (state: CircleState = new CircleState(), action: ICir
return {
...state,
userTies: {
...state.userTies,
...filteredUserTies
}
},
selectedCircles : getSelectedCircles(filteredUserTies)
}
/**
@@ -208,8 +213,65 @@ export let circleReducer = (state: CircleState = new CircleState(), action: ICir
}
}
/**
* User box component
*/
case CircleActionType.SET_SELECTED_CIRCLES_USER_BOX_COMPONENT:
return {
...state,
selectedCircles: {
...state.selectedCircles,
[payload.userId]: payload.circleList
}
}
/**
* User box component
*/
case CircleActionType.REMOVE_SELECTED_CIRCLES_USER_BOX_COMPONENT:
return {
...state,
selectedCircles: {
...state.selectedCircles,
[payload.userId]: []
}
}
/**
* User box component
*/
case CircleActionType.OPEN_SELECT_CIRCLES_USER_BOX_COMPONENT:
return {
...state,
openSelecteCircles: {
...state.openSelecteCircles,
[payload.userId]: true
}
}
case CircleActionType.CLOSE_SELECT_CIRCLES_USER_BOX_COMPONENT:
return {
...state,
openSelecteCircles: {
...state.openSelecteCircles,
[payload.userId]: false
}
}
default:
return state
}
}
/**
* Map user ties selected to selected circles
*/
const getSelectedCircles = (userTies: {[userId: string]: UserTie }) => {
let selectedCircles: {[userId: string]: string[]} = {}
Object.keys(userTies).forEach((userId: string) => {
const userTie = (userTies as {[userId: string]: UserTie })[userId]
selectedCircles = {
...selectedCircles,
[userTie.userId!]: userTie.circleIdList!
}
})
return selectedCircles
}

View File

@@ -6,101 +6,122 @@
*/
export class GlobalState {
/**
* Set percent of loading progress and visibility for Master component
*
* @type {{
* percent: number,
* visible: Boolean
* }}
* @memberof IGlobalState
*/
/**
* Set percent of loading progress and visibility for Master component
*
* @type {{
* percent: number,
* visible: boolean
* }}
* @memberof IGlobalState
*/
progress: {
percent: number
visible: Boolean
visible: boolean
} = {
percent: 0,
visible: false
}
/**
* If loading is enabled {true} or not false
*
* @type {Boolean}
* @memberof IGlobalState
*/
loadingStatus: Boolean = true
/**
* If loading is enabled {true} or not false
*
* @type {boolean}
* @memberof IGlobalState
*/
loadingStatus: boolean = true
/**
* If user date is loaded {true} or not {false}
*
* @type {Boolean}
* @memberof IGlobalState
*/
defaultLoadDataStatus: Boolean = false
/**
* Whether send feedback is diplayed
*/
sendFeedbackStatus: boolean = false
/**
* If message popup is open {true} or not {false}
*
* @type {Boolean}
* @memberof IGlobalState
*/
messageOpen: Boolean = false
/**
* If user date is loaded {true} or not {false}
*
* @type {boolean}
* @memberof IGlobalState
*/
defaultLoadDataStatus: boolean = false
/**
* The text of popup global message
*
* @type {string}
* @memberof IGlobalState
*/
/**
* If message popup is open {true} or not {false}
*
* @type {boolean}
* @memberof IGlobalState
*/
messageOpen: boolean = false
/**
* The text of popup global message
*
* @type {string}
* @memberof IGlobalState
*/
message: string = ''
/**
* Window size
*
* @type {number}
* @memberof IGlobalState
*/
/**
* Window size
*
* @type {number}
* @memberof IGlobalState
*/
windowWidth: number = 0
/**
* Window height
*
* @type {number}
* @memberof IGlobalState
*/
/**
* Window height
*
* @type {number}
* @memberof IGlobalState
*/
windowHeight: number = 0
/**
* The text of website header
*
* @type {string}
* @memberof IGlobalState
*/
/**
* The text of website header
*
* @type {string}
* @memberof IGlobalState
*/
headerTitle: string = ''
/**
* Top loading is visible {true} or not {false}
*
* @type {Boolean}
* @memberof IGlobalState
*/
showTopLoading: Boolean = false
/**
* Top loading is visible {true} or not {false}
*
* @type {boolean}
* @memberof IGlobalState
*/
showTopLoading: boolean = false
/**
* Top loading message queue
*
* @type {number}
* @memberof IGlobalState
*/
/**
* Top loading message queue
*
* @type {number}
* @memberof IGlobalState
*/
topLoadingQueue: number = 0
/**
* Temp date storage
*
* @type {*}
* @memberof IGlobalState
*/
/**
* Master loading is visible {true} or not {false}
*
* @type {boolean}
* @memberof IGlobalState
*/
showMasterLoading: boolean = true
/**
* Master loading message queue
*
* @type {number}
* @memberof IGlobalState
*/
masterLoadingQueue: number = 0
/**
* Temp date storage
*
* @type {*}
* @memberof IGlobalState
*/
temp: any = {
caller: []
}

View File

@@ -67,12 +67,22 @@ export const globalReducer = (state: GlobalState = new GlobalState(), action: IG
...state,
headerTitle: action.payload
}
case GlobalActionType.HIDE_TOP_LOADING:
const queue = state.topLoadingQueue > 0 ? (state.topLoadingQueue - 1) : 0
case GlobalActionType.SHOW_SEND_FEEDBACK:
return {
...state,
topLoadingQueue: queue,
showTopLoading: (queue > 0 ? true : false)
sendFeedbackStatus: true
}
case GlobalActionType.HIDE_SEND_FEEDBACK:
return {
...state,
sendFeedbackStatus: false
}
case GlobalActionType.HIDE_TOP_LOADING:
const queueTopLoading = state.topLoadingQueue > 0 ? (state.topLoadingQueue - 1) : 0
return {
...state,
topLoadingQueue: queueTopLoading,
showTopLoading: (queueTopLoading > 0 ? true : false)
}
case GlobalActionType.SHOW_TOP_LOADING:
@@ -81,6 +91,20 @@ export const globalReducer = (state: GlobalState = new GlobalState(), action: IG
topLoadingQueue: (state.topLoadingQueue + 1),
showTopLoading: true
}
case GlobalActionType.HIDE_MASTER_LOADING:
const queueMasterLoading = state.masterLoadingQueue > 0 ? (state.masterLoadingQueue - 1) : 0
return {
...state,
masterLoadingQueue: queueMasterLoading,
showMasterLoading: (queueMasterLoading > 0 ? true : false)
}
case GlobalActionType.SHOW_MASTER_LOADING:
return {
...state,
masterLoadingQueue: (state.masterLoadingQueue + 1),
showMasterLoading: true
}
case GlobalActionType.TEMP:
return {
...state,

View File

@@ -28,7 +28,7 @@ export let serverReducer = (state: ServerState = new ServerState(), action: ISer
request: {
...state.request,
[request.id]: {
request
...request
}
}
}

View File

@@ -7,7 +7,7 @@ import CommonAPI from 'api/CommonAPI'
/**
* Developer tools
*/
(window as any).logger = CommonAPI.logger
console.trace = CommonAPI.logger
/**
* Initialize container

View File

@@ -2,11 +2,13 @@
@import 'base/grid';
@import 'base/animate';
@import 'base/icon';
@import 'base/flaticon';
// Component styles
@import 'components/global';
@import 'components/master';
@import 'components/post';
@import 'components/profile';
@import 'components/sendFeedback';
@import 'components/userBox';
@import 'components/imageGallery';
@import 'components/postWrite';

View File

@@ -0,0 +1,52 @@
/*
Flaticon icon font: Flaticon
*/
@font-face {
font-family: "Flaticon";
src: url("../assets/fonts/Flaticon.eot");
src: url("../assets/fonts/Flaticon.eot?#iefix") format("embedded-opentype"),
url("../assets/fonts/Flaticon.woff") format("woff"),
url("../assets/fonts/Flaticon.ttf") format("truetype"),
url("../assets/images/Flaticon.svg#Flaticon") format("svg");
font-weight: normal;
font-style: normal;
}
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: "Flaticon";
src: url("../assets/images/Flaticon.svg#Flaticon") format("svg");
}
}
.fi:before{
display: inline-block;
font-family: "Flaticon";
font-style: normal;
font-weight: normal;
font-variant: normal;
line-height: 1;
text-decoration: inherit;
text-rendering: optimizeLegibility;
text-transform: none;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
font-smoothing: antialiased;
}
.flaticon-sad-2:before { content: "\f100"; }
.flaticon-sad-1:before { content: "\f101"; }
.flaticon-neutral:before { content: "\f102"; }
.flaticon-happy-2:before { content: "\f103"; }
.flaticon-sad:before { content: "\f104"; }
.flaticon-happy-1:before { content: "\f105"; }
.flaticon-happy:before { content: "\f106"; }
$font-Flaticon-sad-2: "\f100";
$font-Flaticon-sad-1: "\f101";
$font-Flaticon-neutral: "\f102";
$font-Flaticon-happy-2: "\f103";
$font-Flaticon-sad: "\f104";
$font-Flaticon-happy-1: "\f105";
$font-Flaticon-happy: "\f106";

View File

@@ -35,4 +35,14 @@
background-image: icon(facebook, #4267b2);
}
.icon__svg {
padding: 10px;
display: block;
font-family: "Flaticon";
font-size: 64px;
line-height: 1;
transform: translate(-10px, -9px);
}
// .icon-dashstroke { background-image: icon(heart, red, black, 2, 'stroke-dasharray : 2px, 1px;'); }

View File

@@ -65,8 +65,7 @@
outline: none !important;
box-shadow: 0 2px 10px rgba(0, 0, 0, .2) !important;
div.container {
padding: 10px;
padding: 10px;
padding: 10px 0px 10px 0px;
display: flex;
flex-direction: column;
width: 100%;
@@ -86,16 +85,18 @@
padding: 10px 0px;
div.item {
width: 100%;
height: 68px;
height: 54px;
background-color: white;
margin-bottom: 10px;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
display: flex;
padding: 10px;
padding: 10px 0px 10px 0px;
flex-direction: row;
align-items: center;
position: relative;
div.avatar {}
div.avatar {
margin-left: 5px;
}
div.info {
margin-left: 10px;
height: 100%;

View File

@@ -2,11 +2,37 @@
background-color: rgb(216, 216, 216);
}
.mLoading__content {
max-width: 338px !important;
}
.mLoading__context{
display: flex;
justify-content: space-around;
}
.mLoading__loading {
position: fixed;
z-index: 2001;
height: 2em;
width: 2em;
overflow: show;
margin: auto;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
/* Transparent Overlay */
.mLoading__loading:before {
content: '';
display: block;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.65);
}
/* :not(:required) hides these rules from IE9 and below */
.mLoading__loading:not(:required) {
/* hide "mLoading__loading..." text */
font: 0/0 a;
color: transparent;
text-shadow: none;
background-color: transparent;
border: 0;
}

View File

@@ -0,0 +1,37 @@
.sendFeedback__content {
position: fixed;
right: 5px;
bottom: 5px;
z-index: 1;
.paper {
width: 350px;
height: 100%;
margin: 20px;
text-align: center;
}
.buttons {
position: relative;
}
.close {
position: absolute;
top: 13px;
right: 13px;
}
.success {
padding: 30px;
}
.error {
padding: 30px;
}
.loading{
padding: 18px 0px 0px 0px;
.icon {
justify-content: center;
align-items: center;
align-content: center;
align-self: center;
}
}
}