From 051cfa6f073db85ad95dab658bc0a079b7286f0d Mon Sep 17 00:00:00 2001 From: Qolzam Date: Sun, 14 Jan 2018 15:10:00 +0700 Subject: [PATCH] [Next Version] Realat to #5 #6 #9 #15 #17 #20 #23 #24 #27 #35 #36 #42 --- README.md | 119 +++++---- docs/README.md | 119 +++++---- docs/layers/api.md | 16 -- package.json | 3 +- src/actions/circleActions.ts | 210 ++++++++++++++-- src/actions/commentActions.ts | 2 +- src/actions/globalActions.ts | 169 ++++++++++--- .../{serveActions.ts => serverActions.ts} | 2 +- src/api/CircleAPI.ts | 47 ---- src/api/CommonAPI.ts | 14 +- src/assets/fonts/Flaticon.eot | Bin 0 -> 2902 bytes src/assets/fonts/Flaticon.ttf | Bin 0 -> 2724 bytes src/assets/fonts/Flaticon.woff | Bin 0 -> 1608 bytes src/assets/images/Flaticon.svg | 65 +++++ src/components/circle/CircleComponent.tsx | 36 ++- .../circle/ICircleComponentProps.ts | 9 +- .../findPeople/IFindPeopleComponentProps.ts | 2 +- .../followers/FollowersComponent.tsx | 3 +- .../following/FollowingComponent.tsx | 4 +- src/components/home/HomeComponent.tsx | 13 +- src/components/home/IHomeComponentProps.ts | 10 + .../master/IMasterComponentProps.ts | 13 +- src/components/master/MasterComponent.tsx | 23 +- .../masterLoading/MasterLoadingComponent.tsx | 29 +-- .../ISendFeedbackComponentProps.ts | 30 +++ .../ISendFeedbackComponentState.ts | 7 + .../sendFeedback/SendFeedbackComponent.tsx | 232 ++++++++++++++++++ src/components/sendFeedback/index.ts | 2 + src/components/signup/SignupComponent.tsx | 2 +- .../userBox/IUserBoxComponentProps.ts | 65 ++++- .../userBox/IUserBoxComponentState.ts | 12 - src/components/userBox/UserBoxComponent.tsx | 154 +++++++----- .../yourCircles/YourCirclesComponent.tsx | 2 - src/constants/circleActionType.ts | 4 + src/constants/globalActionType.ts | 4 + src/constants/serverRequestType.ts | 4 +- src/core/domain/circles/circle.ts | 4 +- src/core/domain/common/feed.ts | 34 +++ src/core/domain/common/feedType.ts | 8 + src/core/domain/common/index.ts | 6 +- src/core/services/circles/IUserTieService.ts | 6 + src/core/services/common/ICommonService.ts | 5 + .../services/circles/UserTieService.ts | 30 ++- .../services/common/CommonService.ts | 20 +- .../services/graphs/GraphService.ts | 33 +-- .../services/posts/PostService.ts | 2 +- .../services/users/UserService.ts | 12 +- src/reducers/circles/CircleState.ts | 50 ++-- src/reducers/circles/circleReducer.ts | 70 +++++- src/reducers/global/GlobalState.ts | 169 +++++++------ src/reducers/global/globalReducer.ts | 32 ++- src/reducers/server/serverReducer.ts | 2 +- src/socialEngine.ts | 2 +- src/styles/app.scss | 2 + src/styles/base/_flaticon.scss | 52 ++++ src/styles/base/_icon.scss | 10 + src/styles/components/_homeHeader.scss | 11 +- src/styles/components/_masterLoading.scss | 42 +++- src/styles/components/_sendFeedback.scss | 37 +++ 59 files changed, 1570 insertions(+), 495 deletions(-) rename src/actions/{serveActions.ts => serverActions.ts} (94%) delete mode 100644 src/api/CircleAPI.ts create mode 100644 src/assets/fonts/Flaticon.eot create mode 100644 src/assets/fonts/Flaticon.ttf create mode 100644 src/assets/fonts/Flaticon.woff create mode 100644 src/assets/images/Flaticon.svg create mode 100644 src/components/sendFeedback/ISendFeedbackComponentProps.ts create mode 100644 src/components/sendFeedback/ISendFeedbackComponentState.ts create mode 100644 src/components/sendFeedback/SendFeedbackComponent.tsx create mode 100644 src/components/sendFeedback/index.ts create mode 100644 src/core/domain/common/feed.ts create mode 100644 src/core/domain/common/feedType.ts create mode 100644 src/styles/base/_flaticon.scss create mode 100644 src/styles/components/_sendFeedback.scss diff --git a/README.md b/README.md index 51c0db8..de84b1d 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,13 @@

- React Social Network + React Social Network :rocket: Version NEXT! :rocket:

[![Gitter](https://badges.gitter.im/react-social-network/Lobby.svg)](https://gitter.im/react-social-network/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -The React Social Network is an open source project relying on [React](https://facebook.github.io/react/docs/hello-world.html) a powerful javascript library for building the user interface. In this project, I tried to show some features of react/react components as a social network. +The React Social Network is an open source project relying on [React](https://facebook.github.io/react/docs/hello-world.html) a powerful javascript library for building the user interface. In this project, I tried to show some features of react/react components as a social network. +The structure of this project give the ability to devoloper to develop their project on thier own idea and environment.

@@ -27,9 +28,9 @@ For those who prefer writing code by typescript, now React Social Network suppor This project adheres to the Contributor Covenant [code of conduct](https://github.com/Qolzam/react-social-network/blob/master/CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to amir.gholzam@live.com. -## DEMO +## Example - [Green Open Social](http://greensocial.herokuapp.com) + [Love Open Social](https://love-social.firebaseapp.com) ## Required Knowledge @@ -39,44 +40,37 @@ I recommend that you get to know React before using React Social Network. React ## Document - Use [Documentation](https://qolzam.gitbooks.io/react-social-network/) to find out more details about this project. - -## Features - - * [TypeScript](https://www.typescriptlang.org/) TypeScript is a superset of JavaScript that compiles to clean JavaScript output. - * [React](https://facebook.github.io/react/docs/hello-world.html) A javascript library for building user interfaces. - * [Redux](http://redux.js.org/) is a predictable state container for JavaScript apps. - * [Material-UI](http://www.material-ui.com/#/) A Set of React Components that Implement Google's Material Design. - * [react-redux](https://github.com/reactjs/react-redux) Official React bindings for Redux. - * [Firebase](https://firebase.google.com/) products like Analytics, Realtime Database, Messaging, and Crash Reporting let you move quickly and focus on your users. - * [redux-thunk](https://github.com/gaearon/redux-thunk) Redux Thunk middleware allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. The inner function receives the store methods dispatch and getState as parameters. - * [Express](https://expressjs.com/) Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications. - * [React Router V4](https://github.com/ReactTraining/react-router) for routing website location - * [Sass](http://sass-lang.com/) CSS with superpowers. Sass boasts more features and abilities than any other CSS extension language out there. - * [Webpack](https://webpack.js.org/) for bundling code - -## In my todo list - - * Documentation - * Testing - * Security issues - * Performance - * Add some features and solving bugs - * Sharing post in social itself and other socials - * Add link feature to post - * Add vido post - * Add image gallery post - * Search post and people - ... + Comming soon :) ... -# Prerequisites +## Road map + 1. Support Firebase/Firestore -> on developing + 2. Support AWS -> on developing + 3. Support Azure + 4. Support ASP.NET -> on developing + +## Getting Started + +These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system. + +### Prerequisites Install [NodeJs](https://nodejs.org/en/) + +#### Note -# Installing + - If you're using Windows you should install all node-gyp dependencies with following commands: -[![Build social network in 5 minutes](https://img.youtube.com/vi/E12PNKKjzqA/0.jpg)](https://www.youtube.com/watch?v=E12PNKKjzqA) +`$ npm install --global --production windows-build-tools` +and then install the package + +`$ npm install --global node-gyp` + + +### Installing + +## Install back-end server/serverless + Comming soon :) ... 1. Fork the [react-social-network](https://github.com/Qolzam/react-social-network) repository on Github 2. Clone your fork to your local machine `git clone git@github.com:/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 + + diff --git a/docs/README.md b/docs/README.md index 51c0db8..de84b1d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -6,12 +6,13 @@

- React Social Network + React Social Network :rocket: Version NEXT! :rocket:

[![Gitter](https://badges.gitter.im/react-social-network/Lobby.svg)](https://gitter.im/react-social-network/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -The React Social Network is an open source project relying on [React](https://facebook.github.io/react/docs/hello-world.html) a powerful javascript library for building the user interface. In this project, I tried to show some features of react/react components as a social network. +The React Social Network is an open source project relying on [React](https://facebook.github.io/react/docs/hello-world.html) a powerful javascript library for building the user interface. In this project, I tried to show some features of react/react components as a social network. +The structure of this project give the ability to devoloper to develop their project on thier own idea and environment.

@@ -27,9 +28,9 @@ For those who prefer writing code by typescript, now React Social Network suppor This project adheres to the Contributor Covenant [code of conduct](https://github.com/Qolzam/react-social-network/blob/master/CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to amir.gholzam@live.com. -## DEMO +## Example - [Green Open Social](http://greensocial.herokuapp.com) + [Love Open Social](https://love-social.firebaseapp.com) ## Required Knowledge @@ -39,44 +40,37 @@ I recommend that you get to know React before using React Social Network. React ## Document - Use [Documentation](https://qolzam.gitbooks.io/react-social-network/) to find out more details about this project. - -## Features - - * [TypeScript](https://www.typescriptlang.org/) TypeScript is a superset of JavaScript that compiles to clean JavaScript output. - * [React](https://facebook.github.io/react/docs/hello-world.html) A javascript library for building user interfaces. - * [Redux](http://redux.js.org/) is a predictable state container for JavaScript apps. - * [Material-UI](http://www.material-ui.com/#/) A Set of React Components that Implement Google's Material Design. - * [react-redux](https://github.com/reactjs/react-redux) Official React bindings for Redux. - * [Firebase](https://firebase.google.com/) products like Analytics, Realtime Database, Messaging, and Crash Reporting let you move quickly and focus on your users. - * [redux-thunk](https://github.com/gaearon/redux-thunk) Redux Thunk middleware allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. The inner function receives the store methods dispatch and getState as parameters. - * [Express](https://expressjs.com/) Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications. - * [React Router V4](https://github.com/ReactTraining/react-router) for routing website location - * [Sass](http://sass-lang.com/) CSS with superpowers. Sass boasts more features and abilities than any other CSS extension language out there. - * [Webpack](https://webpack.js.org/) for bundling code - -## In my todo list - - * Documentation - * Testing - * Security issues - * Performance - * Add some features and solving bugs - * Sharing post in social itself and other socials - * Add link feature to post - * Add vido post - * Add image gallery post - * Search post and people - ... + Comming soon :) ... -# Prerequisites +## Road map + 1. Support Firebase/Firestore -> on developing + 2. Support AWS -> on developing + 3. Support Azure + 4. Support ASP.NET -> on developing + +## Getting Started + +These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system. + +### Prerequisites Install [NodeJs](https://nodejs.org/en/) + +#### Note -# Installing + - If you're using Windows you should install all node-gyp dependencies with following commands: -[![Build social network in 5 minutes](https://img.youtube.com/vi/E12PNKKjzqA/0.jpg)](https://www.youtube.com/watch?v=E12PNKKjzqA) +`$ npm install --global --production windows-build-tools` +and then install the package + +`$ npm install --global node-gyp` + + +### Installing + +## Install back-end server/serverless + Comming soon :) ... 1. Fork the [react-social-network](https://github.com/Qolzam/react-social-network) repository on Github 2. Clone your fork to your local machine `git clone git@github.com:/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 + + diff --git a/docs/layers/api.md b/docs/layers/api.md index 9906a4a..24a654e 100644 --- a/docs/layers/api.md +++ b/docs/layers/api.md @@ -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. diff --git a/package.json b/package.json index 320f465..39beb80 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/actions/circleActions.ts b/src/actions/circleActions.ts index 0bf901a..58e959c 100644 --- a/src/actions/circleActions.ts +++ b/src/actions/circleActions.ts @@ -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 } } -} \ No newline at end of file +} diff --git a/src/actions/commentActions.ts b/src/actions/commentActions.ts index 671f26b..ede2d8a 100644 --- a/src/actions/commentActions.ts +++ b/src/actions/commentActions.ts @@ -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 diff --git a/src/actions/globalActions.ts b/src/actions/globalActions.ts index c28a04f..7a9f7b0 100644 --- a/src/actions/globalActions.ts +++ b/src/actions/globalActions.ts @@ -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(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 + ) +} diff --git a/src/actions/serveActions.ts b/src/actions/serverActions.ts similarity index 94% rename from src/actions/serveActions.ts rename to src/actions/serverActions.ts index d650e19..818b6e0 100644 --- a/src/actions/serveActions.ts +++ b/src/actions/serverActions.ts @@ -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} } } diff --git a/src/api/CircleAPI.ts b/src/api/CircleAPI.ts deleted file mode 100644 index 6c90ebc..0000000 --- a/src/api/CircleAPI.ts +++ /dev/null @@ -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 -} diff --git a/src/api/CommonAPI.ts b/src/api/CommonAPI.ts index 4db139f..ceb31dc 100644 --- a/src/api/CommonAPI.ts +++ b/src/api/CommonAPI.ts @@ -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 =========================================`) + } /** diff --git a/src/assets/fonts/Flaticon.eot b/src/assets/fonts/Flaticon.eot new file mode 100644 index 0000000000000000000000000000000000000000..32ec59033fcf2c720ec29153f28bca6ec562af75 GIT binary patch literal 2902 zcmds3Uu;uV82?W1?Y&z!%I(tKJLtf>Zmb=!uD$Krg)9PL>kNWJaD<>iYw6mNt!=gr zhk>LICK8``af!T{5KSP#uqT5rdoTux`k+LVpot;jjYMPcfhhHN?!D{34Se^sC*R+D zzTf@6bME<$w-H@&5ixQQ9}aQ~CIihS#<@dBOhTksdhTnDvAYg^O;@7|C25vYRH7M5 zQ-Sg@x#=inC`*f`WgZ%xjzcp~3-IDTI)(9zP{^cV$UNZsm7wO~H&K}cI+9GjcDTG# zZ6|VFgtmL~*pM;#*Bcc$oq+sSdM;J`?MWw>f5JSNK3mes!^Vh&KG?-D=2A;Vym}G#5pK_?<}&|0_|}I|B696278XkW{K*Bx=h-cq?}qo&9e2mx z+&uc2+N`SlSbl#IcCu(?)j@0(VvAigERX+cWtBo}RWw)PkE{)+scECV>k(s)E zNID-P`#ZAn=keKXKRX7AuhLB-@q9|4e4`=~sz#txsZ<_p=309&sTP>=5Y1uW$wU0l zhq=dTr~P}EZnLc{&u%&Vj<=B!UWbp^6cQm*=mw*q(G^*wN5&1wd4F_8aDb&70#`e^ zdPSDl-=ix?=OZKPiFyK2Pp{|VJJZu_>ghEPi()nG8hcl^qgsB%9VXi0?~la|wbSbs zdi^0b9E(Sd?LwzlQVmt>iFX*PSAt825s&rv`rWM4%T6kqrmLdd+J4j3;Zha3%_WQ4 z_7fAz(w3?85*V^djoqfFxSm zl|a2gf{{+GH^lss+#CO-4%Luxr!M$k3);%DsAEwJrLvIo*CE*yZze z;j>oDEyo|sya4=zcJ+VCb$U`=nGBop8>fHbOunemz%NIV|L;$ z?xO94`?L?JdL*D~KGq4GC{5nWaL#158yHaAUmB`^!RL#|eUq3zUzDHV*Bi_IfobPH zK3txBxaoTJtG^Ye#kv6)?!>gsJMeWoZ}S51eP{C`wJ_^8;5qZ_-9f&(?^8&qud(rX{;q#}>J4t75o0qWuemZ~_r%30}?#!SG%AqyVQRg&H zxsDym+ny2H4SqkoQqbqn8qtA5@!b4OHdoSv=>gpcM@Dw*`-`b`4z_iDQF1m_nn@SX zYc(}mM>E;Q*%Ugiq}gVbOgaw~88bF-w{+Tr*}SBsjUW$$z&BXMNy$RKlq}3=GrAE9 z>wEOI&|o96!N?#-`dozn+4vpL%rDFo@_INN35CO9{kf}EZ+LV+TTrw01060Z>>zm`#UmitjQpbRWF0U_96l19A_i^*!3Zvxv(U literal 0 HcmV?d00001 diff --git a/src/assets/fonts/Flaticon.ttf b/src/assets/fonts/Flaticon.ttf new file mode 100644 index 0000000000000000000000000000000000000000..83df41ba3805753a765cc7a3aba6e26557a54d39 GIT binary patch literal 2724 zcmds3&u&V#+IKajUu>*-?uN^x=Q2~)S6)g>g1|eF}y2i1C65Dbd z8Y+-{s8rNbFO5`gm8w<(iHe*mddZ=xC~A9XQGXy>sY2q0)T*Kf)W-d0z1V9L_yaoD z_`P}W&Ae~FH?yoD#Aa`{rS{l=HGkY z`jAQ_a=40xrLsSNY607!4PAHqH2M10iHFqTfPv`8%Dc-ASzUJ!TgSMKYHo85 zTd%HDsAj-FU&-E_rlo`SlhZWwKxWzwP{_21>=*Vv_p%q+94yn8d`R2q9iSyAc(NMf za38m$b5m!iLi(Rl4Fj+pfX|LV$LI^r6WSH@n|!?|8egCHUTf|oMtqfC5{dIEK{8B4 zCRB|esambx+sdt0V^SkA<0)FxAhPiok7xbwq`AjwkM(<-Zn5nw&u%*WjyJ&wufvCI z7DUJty3S~HVoet5fpJ}O-kn$z98l@Hz|Br>UXvyE&%_$&d|*U9QBNT1>GxcEYi^Fs zZd~=SC|1L+v36xAs^v%CF{0i6!C2f-yS;9q-ydRQv3S(jDRg@!)ljv*c$cAiC4_Vt z@z`L$-_5$c?3AKux+==;oi|)vE>)2`T(YR`JUOjwJW|?kudd!+y?SM3Wp?~@;*P4T zsv>o^w+RSURH3cCQ&Q9;Mli@Sh+DnA@%74;mBi`sSv$TCJpB&ZO<|%$06#6E$(kIf zL8|GpX&-zN-Uq%$8>nIWtzq%qXu`J+PcIq|cnP4sH#I)$?fvZO_*~SD^EO0rA`k@b zSbsA|+E}zZ;FWBQ);S)GVcn^7Q)lZWRW4UFrNQLI8n=?7vGvun$>k{ zFu_fmKzFske+uLZ&>29x#?Q{t-l?orFH`_+=*#Rci`=I!O{ib z`_9ruYGbwAkUxjQ!j@fv{W!mI#CEJ7L$B$K6nfdx9mu<2=>k2Ed$ATHBIYkkcaqNB zmM&ragLH@rxZBTDiRLLwIVzKmI;U~Ub?neEMQEIcp&vw43icdjhz=Es=S%b1Tv-pM zhjb$x86VaU7E|dQd`W;vVVQXZ7bp+ILaIEUE-c&H3A++fN!LZlahseIaw%WGrAE9>-+S_si8(nFfq*l>k?@~RbRtt)nlI$_a5xeQhr_V6g0nqu{f5Wa&oeuzP+ArulISM{l4$o``b^7FN*~b02h%B z)K~8+7gzWHTP#+P57cdiIeiEN5kptaH_*Zo0HhMeo)D<-*9ZkSo|6aw4u-%B=Dfxi zbrjqq$u!9AfgIsGv=BD|Ckg6^bQmkILZJY7L0lRi>S7>*p|rbSWTX|t<6y836Kb|W z*l5sv1u>9>913Ft2s(Zi>4}L?PKDegj42Q_!cRaeE`bYmIKLkpg>aKdisz)lzDOqI zHm>SG07w*a;(4%NC*(Ily~^@i88tB>DH#Bz38-;~NHh|LC8dsVQ4B>vv{J*zZFB$F zMCr9uP@KoYTr;+0uVjhx#dDyzuM7M_1ey^laIznIhgk*4G1SH@15Xw)s8a>_mEqcc z3tC>o9O z_#%Xb5DCicBp*%;>NhX#NgY!lM8_Vyng-39?M0?g5XX(G=iu?c>*4< zjc33YIg4{yodHGpB2D&E$v7ca;BV+ z7ihOHbQe{&i-v5P0!J^IxxDWl(Ci``iOmA(gaF%J$sA{AB7^5P?N&!6;jV7*vpmwP zV*DWpF{UcO&*IzosYte6-{3+=$mK^*W;CK}kxuic__gFKr!}9Ba!oYkQ|!H&!ZVjB z=O40F`tlncg0auH9a)@LLk_aJ9o`u$$tmlJy!L(@7bMsd)jHVJY0D`iQOA32au$OY zM?)ALyK5|zlv3I#>>=}=ZT)&x_IIgq@`2KU*9OsvOxlNv$IBJr`%Pjj zU$)P+NL=U!@16fhDtotEct}t8(=*P751Psg+e&nlOSHef3p#w#d%nK*qgMGh*|UZ! zR`bX^%N0{bhE%Xp6nEh8RcV^I%5{xd1lLZLUhUlB#tf$it5-BfFC^Gqvvp`i7p(17 z!(XIduYMKao5nQEa=GXEs*Xc`<<4J!U$Ons)s3lk*htX{uJ>HI@$Q1LHm%7;+=`tP z&+^bSX}cpGu-Z&hbq~#9IG6eFn;1S@-zg;f->jb%UNA2d^OoG%S#oBkyhUIoVR?IR7>GFlnWE&bE)mBf~>x1O=gleRWo7#{0p zo&V;;Vc)8}k$4E#$K4+}@>0V%r!nPOfd8(UbAOXE9wY4q594Bj3DiQ?mu$6zDH_c48&US6y2fgo#j9MBf#a%L h{;&iBy&3nPS70E!@7L*5w8d4=D + + + + +Created by FontForge 20160405 at Sun Jan 14 05:05:09 2018 + By Apache +Copyright (c) 2018, Apache + + + + + + + + + + + + + + + diff --git a/src/components/circle/CircleComponent.tsx b/src/components/circle/CircleComponent.tsx index 3d2bd24..f13079d 100644 --- a/src/components/circle/CircleComponent.tsx +++ b/src/components/circle/CircleComponent.tsx @@ -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 { - 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(} - onClick={() => this.props.goTo!(`/${key}`)} + leftAvatar={} + onClick={() => this.props.goTo!(`/${userId}`)} />) }) @@ -176,6 +176,7 @@ export class CircleComponent extends Component

@@ -203,7 +204,7 @@ export class CircleComponent extends Component{this.props.circle.name}} leftIcon={} - 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 diff --git a/src/components/circle/ICircleComponentProps.ts b/src/components/circle/ICircleComponentProps.ts index 1618ad3..b48e234 100644 --- a/src/components/circle/ICircleComponentProps.ts +++ b/src/components/circle/ICircleComponentProps.ts @@ -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 diff --git a/src/components/findPeople/IFindPeopleComponentProps.ts b/src/components/findPeople/IFindPeopleComponentProps.ts index e00b554..c14902a 100644 --- a/src/components/findPeople/IFindPeopleComponentProps.ts +++ b/src/components/findPeople/IFindPeopleComponentProps.ts @@ -20,6 +20,6 @@ export interface IFindPeopleComponentProps { /** * If there are more people {true} or not {false} */ - hasMorePeople: boolean + hasMorePeople?: boolean } diff --git a/src/components/followers/FollowersComponent.tsx b/src/components/followers/FollowersComponent.tsx index c1eac4c..07a0b59 100644 --- a/src/components/followers/FollowersComponent.tsx +++ b/src/components/followers/FollowersComponent.tsx @@ -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 } } diff --git a/src/components/following/FollowingComponent.tsx b/src/components/following/FollowingComponent.tsx index 053cf29..e122891 100644 --- a/src/components/following/FollowingComponent.tsx +++ b/src/components/following/FollowingComponent.tsx @@ -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 diff --git a/src/components/home/HomeComponent.tsx b/src/components/home/HomeComponent.tsx index 06c3550..b85ba61 100644 --- a/src/components/home/HomeComponent.tsx +++ b/src/components/home/HomeComponent.tsx @@ -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 @@ -147,7 +146,7 @@ export class HomeComponent extends Component} /> } /> - } /> + showSendFeedback()} style={{ color: 'rgb(117, 117, 117)' }} leftIcon={} /> @@ -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 } } diff --git a/src/components/home/IHomeComponentProps.ts b/src/components/home/IHomeComponentProps.ts index 736ad85..cb4367c 100644 --- a/src/components/home/IHomeComponentProps.ts +++ b/src/components/home/IHomeComponentProps.ts @@ -98,4 +98,14 @@ export interface IHomeComponentProps { */ loaded?: boolean + /** + * Show send feedback form + */ + showSendFeedback: () => any + + /** + * Hide send feedback form + */ + hideSendFeedback: () => any + } diff --git a/src/components/master/IMasterComponentProps.ts b/src/components/master/IMasterComponentProps.ts index 63e37eb..ad15a0f 100644 --- a/src/components/master/IMasterComponentProps.ts +++ b/src/components/master/IMasterComponentProps.ts @@ -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 + } diff --git a/src/components/master/MasterComponent.tsx b/src/components/master/MasterComponent.tsx index 4d356aa..6214e3d 100644 --- a/src/components/master/MasterComponent.tsx +++ b/src/components/master/MasterComponent.tsx @@ -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 { - 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 - +
Loading ...
- + { }, loadDataGuest: () => { dispatch(globalActions.loadDataGuest()) - } + }, + showMasterLoading: () => dispatch(globalActions.showMasterLoading()), + hideMasterLoading: () => dispatch(globalActions.hideMasterLoading()) } } diff --git a/src/components/masterLoading/MasterLoadingComponent.tsx b/src/components/masterLoading/MasterLoadingComponent.tsx index f3f9529..324b690 100644 --- a/src/components/masterLoading/MasterLoadingComponent.tsx +++ b/src/components/masterLoading/MasterLoadingComponent.tsx @@ -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 { +export default class MasterLoadingComponent extends Component { // Constructor constructor (props: IMasterLoadingComponentProps) { @@ -19,27 +20,19 @@ export default class MasterLoadingComponent extends Component - -
-
- - -

Green

+
+
-
- + ) } diff --git a/src/components/sendFeedback/ISendFeedbackComponentProps.ts b/src/components/sendFeedback/ISendFeedbackComponentProps.ts new file mode 100644 index 0000000..77f34e0 --- /dev/null +++ b/src/components/sendFeedback/ISendFeedbackComponentProps.ts @@ -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 +} diff --git a/src/components/sendFeedback/ISendFeedbackComponentState.ts b/src/components/sendFeedback/ISendFeedbackComponentState.ts new file mode 100644 index 0000000..77d1311 --- /dev/null +++ b/src/components/sendFeedback/ISendFeedbackComponentState.ts @@ -0,0 +1,7 @@ + +export interface ISendFeedbackComponentState { + /** + * Feedback text + */ + feedText: string +} diff --git a/src/components/sendFeedback/SendFeedbackComponent.tsx b/src/components/sendFeedback/SendFeedbackComponent.tsx new file mode 100644 index 0000000..4ce20e4 --- /dev/null +++ b/src/components/sendFeedback/SendFeedbackComponent.tsx @@ -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 { + + /** + * 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 ( +
+
+
+ this.handleSendFeed(FeedType.Sad)} + > + + this.handleSendFeed(FeedType.Acceptable)} + > + + this.handleSendFeed(FeedType.Happy)} + > + + this.handleSendFeed(FeedType.Awesome)} + > + + +
+
) + } + + loadingForm = () => { + return (
+

+ Your feedback is sending! +

+
+ + +
+
) + } + + successForm = () => { + return (
We appreciate your kind support as always ;)
) + } + + errorForm = () => { + return (
Error in sending feedback :(
) + } + + 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 ( +
+ +
+ hideFeedback()} + > + + +
+ {this.getFeedbackForm()} + +
+
+ ) + } +} + +/** + * 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) diff --git a/src/components/sendFeedback/index.ts b/src/components/sendFeedback/index.ts new file mode 100644 index 0000000..3b51954 --- /dev/null +++ b/src/components/sendFeedback/index.ts @@ -0,0 +1,2 @@ +import SendFeedbackComponent from './SendFeedbackComponent' +export default SendFeedbackComponent diff --git a/src/components/signup/SignupComponent.tsx b/src/components/signup/SignupComponent.tsx index 4d2e771..cde6261 100644 --- a/src/components/signup/SignupComponent.tsx +++ b/src/components/signup/SignupComponent.tsx @@ -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) diff --git a/src/components/userBox/IUserBoxComponentProps.ts b/src/components/userBox/IUserBoxComponentProps.ts index 486f9c9..2e9b470 100644 --- a/src/components/userBox/IUserBoxComponentProps.ts +++ b/src/components/userBox/IUserBoxComponentProps.ts @@ -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 } diff --git a/src/components/userBox/IUserBoxComponentState.ts b/src/components/userBox/IUserBoxComponentState.ts index 7a6cbf2..045cdbe 100644 --- a/src/components/userBox/IUserBoxComponentState.ts +++ b/src/components/userBox/IUserBoxComponentState.ts @@ -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[] } diff --git a/src/components/userBox/UserBoxComponent.tsx b/src/components/userBox/UserBoxComponent.tsx index 686d2e5..e2155bd 100644 --- a/src/components/userBox/UserBoxComponent.tsx +++ b/src/components/userBox/UserBoxComponent.tsx @@ -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 { - + /** + * Fields + */ static propTypes = { /** * User identifier @@ -69,6 +73,7 @@ export class UserBoxComponent extends Component { - 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 { + 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 { - this.setState({ - open: true - }) + const { openSelectCircles, userId} = this.props + openSelectCircles!(userId) } /** @@ -170,54 +194,40 @@ export class UserBoxComponent extends Component { - 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 }) + + return parsedDate } } @@ -260,6 +272,7 @@ export class UserBoxComponent extends Component ] - const { isFollowed } = this.props return ( - +
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) + } />
@@ -316,7 +332,7 @@ export class UserBoxComponent extends Component { 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 || '' : '', diff --git a/src/components/yourCircles/YourCirclesComponent.tsx b/src/components/yourCircles/YourCirclesComponent.tsx index 7a9eb4a..d147c6c 100644 --- a/src/components/yourCircles/YourCirclesComponent.tsx +++ b/src/components/yourCircles/YourCirclesComponent.tsx @@ -45,9 +45,7 @@ export class YourCirclesComponent extends Component { - if (key.trim() !== '-Followers') { parsedCircles.push() - } }) } return parsedCircles diff --git a/src/constants/circleActionType.ts b/src/constants/circleActionType.ts index 6ad9cad..1854dd1 100644 --- a/src/constants/circleActionType.ts +++ b/src/constants/circleActionType.ts @@ -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' diff --git a/src/constants/globalActionType.ts b/src/constants/globalActionType.ts index 437f73f..5216b84 100644 --- a/src/constants/globalActionType.ts +++ b/src/constants/globalActionType.ts @@ -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', diff --git a/src/constants/serverRequestType.ts b/src/constants/serverRequestType.ts index ac36989..19cdb87 100644 --- a/src/constants/serverRequestType.ts +++ b/src/constants/serverRequestType.ts @@ -1,6 +1,8 @@ export enum ServerRequestType { CircleAddToCircle = 'CircleAddToCircle', CircleFollowUser = 'CircleFollowUser', - CircleCreateTieUser = 'CircleCreateTieUser' + CircleCreateTieUser = 'CircleCreateTieUser', + CircleDeleteFollowingUser = 'CircleDeleteFollowingUser', + CommonSendFeedback = 'CommonSendFeedback' } diff --git a/src/core/domain/circles/circle.ts b/src/core/domain/circles/circle.ts index 029c316..a5016c6 100644 --- a/src/core/domain/circles/circle.ts +++ b/src/core/domain/circles/circle.ts @@ -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 } diff --git a/src/core/domain/common/feed.ts b/src/core/domain/common/feed.ts new file mode 100644 index 0000000..3f555df --- /dev/null +++ b/src/core/domain/common/feed.ts @@ -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 + + ) { + } + +} diff --git a/src/core/domain/common/feedType.ts b/src/core/domain/common/feedType.ts new file mode 100644 index 0000000..1d4c529 --- /dev/null +++ b/src/core/domain/common/feedType.ts @@ -0,0 +1,8 @@ +export enum FeedType { + Awesome = 'Awesome', + Happy = 'Happey', + Acceptable = 'Acceptable', + Sad = 'Sad', + Bug = 'Bug' + +} diff --git a/src/core/domain/common/index.ts b/src/core/domain/common/index.ts index bfbbe3c..4ac9b5d 100644 --- a/src/core/domain/common/index.ts +++ b/src/core/domain/common/index.ts @@ -1,7 +1,9 @@ import { SocialError } from './socialError' import { BaseDomain } from './baseDomain' +import { Feed } from './feed' export { SocialError, - BaseDomain -} \ No newline at end of file + BaseDomain, + Feed +} diff --git a/src/core/services/circles/IUserTieService.ts b/src/core/services/circles/IUserTieService.ts index 1dd5813..5578f4e 100644 --- a/src/core/services/circles/IUserTieService.ts +++ b/src/core/services/circles/IUserTieService.ts @@ -15,6 +15,12 @@ export interface IUserTieService { tieUseres: (userTieSenderInfo: UserTie, userTieReceiveInfo: UserTie, circleIds: string[]) => Promise + /** + * Update users tie + */ + updateUsersTie: (userTieSenderInfo: UserTie, userTieReceiveInfo: UserTie, circleIds: string[]) + => Promise + /** * Remove users' tie */ diff --git a/src/core/services/common/ICommonService.ts b/src/core/services/common/ICommonService.ts index 2a9f8b9..8b4cb78 100644 --- a/src/core/services/common/ICommonService.ts +++ b/src/core/services/common/ICommonService.ts @@ -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 } diff --git a/src/data/firestoreClient/services/circles/UserTieService.ts b/src/data/firestoreClient/services/circles/UserTieService.ts index 956f67e..ead95d6 100644 --- a/src/data/firestoreClient/services/circles/UserTieService.ts +++ b/src/data/firestoreClient/services/circles/UserTieService.ts @@ -53,6 +53,32 @@ export class UserTieService implements IUserTieService { }) } + /** + * Update users tie + */ + public updateUsersTie: (userTieSenderInfo: UserTie, userTieReceiveInfo: UserTie, circleIds: string[]) + => Promise = (userTieSenderInfo, userTieReceiveInfo, circleIds) => { + return new Promise((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: [] } } diff --git a/src/data/firestoreClient/services/common/CommonService.ts b/src/data/firestoreClient/services/common/CommonService.ts index 6de5cdd..4fdea8d 100644 --- a/src/data/firestoreClient/services/common/CommonService.ts +++ b/src/data/firestoreClient/services/common/CommonService.ts @@ -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 = (feed) => { + return new Promise((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)) + }) + }) + } } diff --git a/src/data/firestoreClient/services/graphs/GraphService.ts b/src/data/firestoreClient/services/graphs/GraphService.ts index 1e7dae4..1e6db68 100644 --- a/src/data/firestoreClient/services/graphs/GraphService.ts +++ b/src/data/firestoreClient/services/graphs/GraphService.ts @@ -34,17 +34,19 @@ export class GraphService implements IGraphService { } /** - * Add graph + * Update graph */ public updateGraph: (graph: Graph, collection: string) => Promise = (graph, collection) => { return new Promise((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 = (collection, leftNode, edgeType, rightNode) => { return new Promise((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 { diff --git a/src/data/firestoreClient/services/posts/PostService.ts b/src/data/firestoreClient/services/posts/PostService.ts index 35d6626..81811d2 100644 --- a/src/data/firestoreClient/services/posts/PostService.ts +++ b/src/data/firestoreClient/services/posts/PostService.ts @@ -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 diff --git a/src/data/firestoreClient/services/users/UserService.ts b/src/data/firestoreClient/services/users/UserService.ts index 7e21145..c824ecb 100644 --- a/src/data/firestoreClient/services/users/UserService.ts +++ b/src/data/firestoreClient/services/users/UserService.ts @@ -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((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)) }) }) diff --git a/src/reducers/circles/CircleState.ts b/src/reducers/circles/CircleState.ts index f207a1b..e0c5967 100644 --- a/src/reducers/circles/CircleState.ts +++ b/src/reducers/circles/CircleState.ts @@ -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 } diff --git a/src/reducers/circles/circleReducer.ts b/src/reducers/circles/circleReducer.ts index 2aeca22..f9d92e1 100644 --- a/src/reducers/circles/circleReducer.ts +++ b/src/reducers/circles/circleReducer.ts @@ -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 +} \ No newline at end of file diff --git a/src/reducers/global/GlobalState.ts b/src/reducers/global/GlobalState.ts index 659163e..bab07e1 100644 --- a/src/reducers/global/GlobalState.ts +++ b/src/reducers/global/GlobalState.ts @@ -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: [] } diff --git a/src/reducers/global/globalReducer.ts b/src/reducers/global/globalReducer.ts index 1e7ef9e..1ee8b85 100644 --- a/src/reducers/global/globalReducer.ts +++ b/src/reducers/global/globalReducer.ts @@ -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, diff --git a/src/reducers/server/serverReducer.ts b/src/reducers/server/serverReducer.ts index 97f14c1..30cd337 100644 --- a/src/reducers/server/serverReducer.ts +++ b/src/reducers/server/serverReducer.ts @@ -28,7 +28,7 @@ export let serverReducer = (state: ServerState = new ServerState(), action: ISer request: { ...state.request, [request.id]: { - request + ...request } } } diff --git a/src/socialEngine.ts b/src/socialEngine.ts index 58bbf61..98816b5 100644 --- a/src/socialEngine.ts +++ b/src/socialEngine.ts @@ -7,7 +7,7 @@ import CommonAPI from 'api/CommonAPI' /** * Developer tools */ -(window as any).logger = CommonAPI.logger +console.trace = CommonAPI.logger /** * Initialize container diff --git a/src/styles/app.scss b/src/styles/app.scss index c1f60de..2f7e4f4 100644 --- a/src/styles/app.scss +++ b/src/styles/app.scss @@ -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'; diff --git a/src/styles/base/_flaticon.scss b/src/styles/base/_flaticon.scss new file mode 100644 index 0000000..a476de6 --- /dev/null +++ b/src/styles/base/_flaticon.scss @@ -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"; \ No newline at end of file diff --git a/src/styles/base/_icon.scss b/src/styles/base/_icon.scss index 9895dd5..6870593 100644 --- a/src/styles/base/_icon.scss +++ b/src/styles/base/_icon.scss @@ -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;'); } \ No newline at end of file diff --git a/src/styles/components/_homeHeader.scss b/src/styles/components/_homeHeader.scss index 7f46a9f..bd0ce6b 100644 --- a/src/styles/components/_homeHeader.scss +++ b/src/styles/components/_homeHeader.scss @@ -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%; diff --git a/src/styles/components/_masterLoading.scss b/src/styles/components/_masterLoading.scss index f81bc82..920a296 100644 --- a/src/styles/components/_masterLoading.scss +++ b/src/styles/components/_masterLoading.scss @@ -2,11 +2,37 @@ background-color: rgb(216, 216, 216); } -.mLoading__content { - max-width: 338px !important; -} - -.mLoading__context{ - display: flex; - justify-content: space-around; -} \ No newline at end of file +.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; + } \ No newline at end of file diff --git a/src/styles/components/_sendFeedback.scss b/src/styles/components/_sendFeedback.scss new file mode 100644 index 0000000..e7e995f --- /dev/null +++ b/src/styles/components/_sendFeedback.scss @@ -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; + } + } +} \ No newline at end of file