119
README.md
119
README.md
@@ -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>
|
||||
|
||||
[](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:
|
||||
|
||||
[](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
|
||||
|
||||
|
||||
|
||||
119
docs/README.md
119
docs/README.md
@@ -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>
|
||||
|
||||
[](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:
|
||||
|
||||
[](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
|
||||
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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} }
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 =========================================`)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
BIN
src/assets/fonts/Flaticon.eot
Normal file
BIN
src/assets/fonts/Flaticon.eot
Normal file
Binary file not shown.
BIN
src/assets/fonts/Flaticon.ttf
Normal file
BIN
src/assets/fonts/Flaticon.ttf
Normal file
Binary file not shown.
BIN
src/assets/fonts/Flaticon.woff
Normal file
BIN
src/assets/fonts/Flaticon.woff
Normal file
Binary file not shown.
65
src/assets/images/Flaticon.svg
Normal file
65
src/assets/images/Flaticon.svg
Normal 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=""
|
||||
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=""
|
||||
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=""
|
||||
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=""
|
||||
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=""
|
||||
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=""
|
||||
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=""
|
||||
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 |
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -20,6 +20,6 @@ export interface IFindPeopleComponentProps {
|
||||
/**
|
||||
* If there are more people {true} or not {false}
|
||||
*/
|
||||
hasMorePeople: boolean
|
||||
hasMorePeople?: boolean
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -98,4 +98,14 @@ export interface IHomeComponentProps {
|
||||
*/
|
||||
loaded?: boolean
|
||||
|
||||
/**
|
||||
* Show send feedback form
|
||||
*/
|
||||
showSendFeedback: () => any
|
||||
|
||||
/**
|
||||
* Hide send feedback form
|
||||
*/
|
||||
hideSendFeedback: () => any
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
30
src/components/sendFeedback/ISendFeedbackComponentProps.ts
Normal file
30
src/components/sendFeedback/ISendFeedbackComponentProps.ts
Normal 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
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
export interface ISendFeedbackComponentState {
|
||||
/**
|
||||
* Feedback text
|
||||
*/
|
||||
feedText: string
|
||||
}
|
||||
232
src/components/sendFeedback/SendFeedbackComponent.tsx
Normal file
232
src/components/sendFeedback/SendFeedbackComponent.tsx
Normal 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)
|
||||
2
src/components/sendFeedback/index.ts
Normal file
2
src/components/sendFeedback/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
import SendFeedbackComponent from './SendFeedbackComponent'
|
||||
export default SendFeedbackComponent
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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[]
|
||||
}
|
||||
|
||||
@@ -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 || '' : '',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
export enum ServerRequestType {
|
||||
CircleAddToCircle = 'CircleAddToCircle',
|
||||
CircleFollowUser = 'CircleFollowUser',
|
||||
CircleCreateTieUser = 'CircleCreateTieUser'
|
||||
CircleCreateTieUser = 'CircleCreateTieUser',
|
||||
CircleDeleteFollowingUser = 'CircleDeleteFollowingUser',
|
||||
CommonSendFeedback = 'CommonSendFeedback'
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
34
src/core/domain/common/feed.ts
Normal file
34
src/core/domain/common/feed.ts
Normal 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
|
||||
|
||||
) {
|
||||
}
|
||||
|
||||
}
|
||||
8
src/core/domain/common/feedType.ts
Normal file
8
src/core/domain/common/feedType.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export enum FeedType {
|
||||
Awesome = 'Awesome',
|
||||
Happy = 'Happey',
|
||||
Acceptable = 'Acceptable',
|
||||
Sad = 'Sad',
|
||||
Bug = 'Bug'
|
||||
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
import { SocialError } from './socialError'
|
||||
import { BaseDomain } from './baseDomain'
|
||||
import { Feed } from './feed'
|
||||
|
||||
export {
|
||||
SocialError,
|
||||
BaseDomain
|
||||
}
|
||||
BaseDomain,
|
||||
Feed
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
@@ -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: []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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: []
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -28,7 +28,7 @@ export let serverReducer = (state: ServerState = new ServerState(), action: ISer
|
||||
request: {
|
||||
...state.request,
|
||||
[request.id]: {
|
||||
request
|
||||
...request
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import CommonAPI from 'api/CommonAPI'
|
||||
/**
|
||||
* Developer tools
|
||||
*/
|
||||
(window as any).logger = CommonAPI.logger
|
||||
console.trace = CommonAPI.logger
|
||||
|
||||
/**
|
||||
* Initialize container
|
||||
|
||||
@@ -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';
|
||||
|
||||
52
src/styles/base/_flaticon.scss
Normal file
52
src/styles/base/_flaticon.scss
Normal 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";
|
||||
@@ -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;'); }
|
||||
@@ -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%;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
37
src/styles/components/_sendFeedback.scss
Normal file
37
src/styles/components/_sendFeedback.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user