From 9ffd6a1e4064c7810448910b88fa2012c1fedd26 Mon Sep 17 00:00:00 2001 From: Qolzam Date: Sat, 11 Nov 2017 11:02:37 +0700 Subject: [PATCH] Image gallery has been resolved --- .gitignore | 4 +- src/actions/imageGalleryActions.ts | 11 +++-- src/api/StringAPI.ts | 3 -- .../IImageGalleryComponentProps.ts | 15 ++----- .../imageGallery/ImageGalleryComponent.tsx | 14 ++----- src/components/master/MasterComponent.tsx | 11 ++++- src/components/post/PostComponent.tsx | 1 + src/core/factories/IServiceProvider.ts | 28 +++++++++---- src/core/factories/serviceProvide.ts | 15 ++++++- .../services/authorize/IAuthorizeService.ts | 8 +++- src/core/services/files/IStorageService.ts | 11 +++++ src/core/services/files/index.ts | 5 +++ .../imageGallery/IImageGalleryService.ts | 3 +- src/core/services/index.ts | 4 +- .../services/authorize/AuthorizeService.ts | 9 ++++ .../services/files/StorageService.ts | 41 +++++++++++++++++++ .../firebaseClient/services/files/index.ts | 5 +++ .../imageGallery/ImageGalleryService.ts | 36 ++++++++-------- src/data/firebaseClient/services/index.ts | 5 ++- .../services/posts/PostService.ts | 10 ++--- src/models/files/fileResult.ts | 15 +++++++ src/models/files/index.ts | 1 + src/tests/actions/authorizeActions.test.jsx | 34 --------------- 23 files changed, 186 insertions(+), 103 deletions(-) create mode 100644 src/core/services/files/IStorageService.ts create mode 100644 src/core/services/files/index.ts create mode 100644 src/data/firebaseClient/services/files/StorageService.ts create mode 100644 src/data/firebaseClient/services/files/index.ts create mode 100644 src/models/files/fileResult.ts create mode 100644 src/models/files/index.ts delete mode 100644 src/tests/actions/authorizeActions.test.jsx diff --git a/.gitignore b/.gitignore index d6945962..d3325e4d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ public/bundle.js config/ .vscode/ src/data/awsClient -src/components/AWS.tsx \ No newline at end of file +src/components/AWS.tsx +.firebaserc +firebase.json \ No newline at end of file diff --git a/src/actions/imageGalleryActions.ts b/src/actions/imageGalleryActions.ts index 27a3077f..c09cd6cf 100644 --- a/src/actions/imageGalleryActions.ts +++ b/src/actions/imageGalleryActions.ts @@ -1,3 +1,4 @@ +import { IStorageService } from 'core/services/files' // - Import react componetns import moment from 'moment' @@ -16,9 +17,11 @@ import FileAPI from 'api/FileAPI' import { IServiceProvider, ServiceProvide } from 'core/factories' import { IImageGalleryService } from 'core/services/imageGallery' +import { FileResult } from 'models/files/fileResult' const serviceProvider: IServiceProvider = new ServiceProvide() const imageGalleryService: IImageGalleryService = serviceProvider.createImageGalleryService() +const storageService: IStorageService = serviceProvider.createStorageService() /* _____________ UI Actions _____________ */ @@ -101,16 +104,16 @@ export const dbDeleteImage = (id: string) => { * @param {file} file * @param {string} fileName */ -export const dbUploadImage = (file: any, fileName: string) => { +export const dbUploadImage = (image: any, imageName: string) => { return (dispatch: any, getState: Function) => { return imageGalleryService - .uploadImage(file,fileName, (percentage: number) => { + .uploadImage(image,imageName, (percentage: number) => { dispatch(globalActions.progressChange(percentage, true)) }) - .then(() => { + .then((result: FileResult) => { dispatch(globalActions.progressChange(100, false)) - dispatch(dbSaveImage(fileName,'')) + dispatch(dbSaveImage(result.fileURL,result.fileFullPath)) dispatch(globalActions.hideTopLoading()) }) .catch((error: SocialError) => { diff --git a/src/api/StringAPI.ts b/src/api/StringAPI.ts index e3342460..5144157b 100644 --- a/src/api/StringAPI.ts +++ b/src/api/StringAPI.ts @@ -1,6 +1,3 @@ -// - Import react component -import { storageRef } from 'data/firebaseClient' - // - Import actions const isValidEmail = (email: string) => { diff --git a/src/components/imageGallery/IImageGalleryComponentProps.ts b/src/components/imageGallery/IImageGalleryComponentProps.ts index 9bcaa32d..2f40d75e 100644 --- a/src/components/imageGallery/IImageGalleryComponentProps.ts +++ b/src/components/imageGallery/IImageGalleryComponentProps.ts @@ -8,7 +8,7 @@ export interface IImageGalleryComponentProps { * @type {(URL: string,fullPath: string)} * @memberof IImageGalleryComponentProps */ - set?: (URL: string,fullPath: string) => void + set: (URL: string,fullPath: string) => void /** * Delete an image @@ -18,25 +18,18 @@ export interface IImageGalleryComponentProps { deleteImage?: (imageId: string) => void /** - * Save image in image gallery + * Upload image to the server * * @memberof IImageGalleryComponentProps */ - saveImageGallery?: (URL: string,fullPath: string) => void - - /** - * Change progress state - * - * @memberof IImageGalleryComponentProps - */ - progressChange?: (percentage: number, status: boolean) => void + uploadImage?: (image: any, imageName: string) => any /** * Close image gallery * * @memberof IImageGalleryComponentProps */ - close?: () => void + close: () => void /** * List of image in image gallery diff --git a/src/components/imageGallery/ImageGalleryComponent.tsx b/src/components/imageGallery/ImageGalleryComponent.tsx index b7db79ac..f2c0ad02 100644 --- a/src/components/imageGallery/ImageGalleryComponent.tsx +++ b/src/components/imageGallery/ImageGalleryComponent.tsx @@ -124,16 +124,8 @@ export class ImageGalleryComponent extends Component { const { resizedImage, fileName } = event.detail - const {saveImageGallery, progressChange} = this.props - - FileAPI.uploadImage(resizedImage, fileName, (percent: number, status: boolean) => { - progressChange!(percent,status) - }).then((result) => { - - /* Add image to image gallery */ - saveImageGallery!(result.downloadURL,result.metadata.fullPath) - - }) + const {uploadImage} = this.props + uploadImage(resizedImage,fileName) } /** @@ -231,7 +223,7 @@ export class ImageGalleryComponent extends Component { return { - saveImageGallery: (imageURL: string,imageFullPath: string) => dispatch(imageGalleryActions.dbSaveImage(imageURL,imageFullPath)), + uploadImage: (image: any, imageName: string) => dispatch(imageGalleryActions.dbUploadImage(image,imageName)), deleteImage: (id: string) => dispatch(imageGalleryActions.dbDeleteImage(id)), progressChange : (percent: number,status: boolean) => dispatch(globalActions.progressChange(percent, status)) diff --git a/src/components/master/MasterComponent.tsx b/src/components/master/MasterComponent.tsx index a75ec505..b50e569f 100644 --- a/src/components/master/MasterComponent.tsx +++ b/src/components/master/MasterComponent.tsx @@ -3,7 +3,6 @@ import React, { Component } from 'react' import { connect } from 'react-redux' import { Route, Switch, NavLink, withRouter, Redirect } from 'react-router-dom' -import { firebaseAuth, firebaseRef } from 'data/firebaseClient' import { push } from 'react-router-redux' import Snackbar from 'material-ui/Snackbar' import LinearProgress from 'material-ui/LinearProgress' @@ -16,6 +15,8 @@ import Setting from 'components/setting' import MasterLoading from 'components/masterLoading' import { IMasterComponentProps } from './IMasterComponentProps' import { IMasterComponentState } from './IMasterComponentState' +import { ServiceProvide, IServiceProvider } from 'core/factories' +import { IAuthorizeService } from 'core/services/authorize' // - Import actions import { @@ -36,9 +37,15 @@ import { export class MasterComponent extends Component { static isPrivate = true + + private readonly _serviceProvider: IServiceProvider + private readonly _authourizeService: IAuthorizeService // Constructor constructor (props: IMasterComponentProps) { super(props) + + this._serviceProvider = new ServiceProvide() + this._authourizeService = this._serviceProvider.createAuthorizeService() this.state = { loading: true, authed: false, @@ -73,7 +80,7 @@ export class MasterComponent extends Component { + this._authourizeService.onAuthStateChanged((user: any) => { if (user) { this.props.login(user) diff --git a/src/components/post/PostComponent.tsx b/src/components/post/PostComponent.tsx index 5b6aadaf..d47a8479 100644 --- a/src/components/post/PostComponent.tsx +++ b/src/components/post/PostComponent.tsx @@ -27,6 +27,7 @@ import Dialog from 'material-ui/Dialog' import IconButton from 'material-ui/IconButton' import MoreVertIcon from 'material-ui/svg-icons/navigation/more-vert' import IconMenu from 'material-ui/IconMenu' + import reactStringReplace from 'react-string-replace' // - Import app components diff --git a/src/core/factories/IServiceProvider.ts b/src/core/factories/IServiceProvider.ts index 9250a6bd..dbe1fd13 100644 --- a/src/core/factories/IServiceProvider.ts +++ b/src/core/factories/IServiceProvider.ts @@ -1,12 +1,15 @@ -import { IAuthorizeService } from 'services/authorize/IAuthorizeService' -import { ICircleService } from 'services/circles' -import { ICommentService } from 'core/services/comments' -import { ICommonService } from 'services/common' -import { IImageGalleryService } from 'services/imageGallery' -import { INotificationService } from 'services/notifications' -import { IPostService } from 'services/posts' -import { IUserService } from 'services/users' -import { IVoteService } from 'services/votes' +import { + IAuthorizeService, + ICircleService, + ICommentService, + ICommonService, + IImageGalleryService, + INotificationService, + IPostService, + IUserService, + IVoteService, + IStorageService +} from 'core/services' export interface IServiceProvider { @@ -73,4 +76,11 @@ export interface IServiceProvider { */ createVoteService: () => IVoteService + /** + * Create instant for Vote Service + * + * @memberof ServiceProvide + */ + createStorageService: () => IStorageService + } diff --git a/src/core/factories/serviceProvide.ts b/src/core/factories/serviceProvide.ts index 4cd2a625..f63f55a8 100644 --- a/src/core/factories/serviceProvide.ts +++ b/src/core/factories/serviceProvide.ts @@ -10,7 +10,8 @@ import { INotificationService, IPostService, IUserService, - IVoteService + IVoteService, + IStorageService } from 'core/services' //#endregion @@ -27,7 +28,8 @@ import { NotificationService, PostService, UserService, - VoteService + VoteService, + StorageService } from 'data/firebaseClient/services' //#endregion @@ -115,4 +117,13 @@ export class ServiceProvide implements IServiceProvider { return new VoteService() } + /** + * Create instant for Vote Service + * + * @memberof ServiceProvide + */ + createStorageService: () => IStorageService = () => { + return new StorageService() + } + } diff --git a/src/core/services/authorize/IAuthorizeService.ts b/src/core/services/authorize/IAuthorizeService.ts index d10d9a6a..d08bfa6b 100644 --- a/src/core/services/authorize/IAuthorizeService.ts +++ b/src/core/services/authorize/IAuthorizeService.ts @@ -35,4 +35,10 @@ export interface IAuthorizeService { */ registerUser: (user: User) => Promise -} \ No newline at end of file + /** + * On user authorization changed event + * + * @memberof IAuthorizeService + */ + onAuthStateChanged: (callBack: (user: User) => void) +} diff --git a/src/core/services/files/IStorageService.ts b/src/core/services/files/IStorageService.ts new file mode 100644 index 00000000..ee3235a3 --- /dev/null +++ b/src/core/services/files/IStorageService.ts @@ -0,0 +1,11 @@ +import { FileResult } from 'models/files/fileResult' + +export interface IStorageService { + + /** + * Storage file service + * + * @memberof IStorageService + */ + uploadFile: (file: any, fileName: string, progress: (percentage: number, status: boolean) => void) => Promise +} diff --git a/src/core/services/files/index.ts b/src/core/services/files/index.ts new file mode 100644 index 00000000..a371966c --- /dev/null +++ b/src/core/services/files/index.ts @@ -0,0 +1,5 @@ +import { IStorageService } from './IStorageService' + +export { + IStorageService +} diff --git a/src/core/services/imageGallery/IImageGalleryService.ts b/src/core/services/imageGallery/IImageGalleryService.ts index bfec2b60..db5bd3b4 100644 --- a/src/core/services/imageGallery/IImageGalleryService.ts +++ b/src/core/services/imageGallery/IImageGalleryService.ts @@ -1,3 +1,4 @@ +import { FileResult } from 'models/files/fileResult' import { User } from 'core/domain/users' import { Image } from 'core/domain/imageGallery' @@ -11,6 +12,6 @@ export interface IImageGalleryService { getImageGallery: (userId: string) => Promise saveImage: (userId: string, image: Image) => Promise deleteImage: (userId: string, imageId: string) => Promise - uploadImage: (file: any, fileName: string, progressCallback: Function) => Promise + uploadImage: (file: any, fileName: string, progressCallback: (percentage: number, status: boolean) => void) => Promise downloadImage: (fileName: string) => Promise } diff --git a/src/core/services/index.ts b/src/core/services/index.ts index 02aedb89..a06538ac 100644 --- a/src/core/services/index.ts +++ b/src/core/services/index.ts @@ -7,6 +7,7 @@ import { INotificationService } from './notifications' import { IPostService } from './posts' import { IUserService } from './users' import { IVoteService } from './votes' +import { IStorageService } from './files' export { IAuthorizeService, @@ -17,5 +18,6 @@ export { INotificationService, IPostService, IUserService, - IVoteService + IVoteService, + IStorageService } diff --git a/src/data/firebaseClient/services/authorize/AuthorizeService.ts b/src/data/firebaseClient/services/authorize/AuthorizeService.ts index b8c0cffc..d8bf76f6 100644 --- a/src/data/firebaseClient/services/authorize/AuthorizeService.ts +++ b/src/data/firebaseClient/services/authorize/AuthorizeService.ts @@ -103,4 +103,13 @@ export class AuthorizeService implements IAuthorizeService { }) } + /** + * On user authorization changed event + * + * @memberof IAuthorizeService + */ + onAuthStateChanged: (callBack: (user: User) => void) => any = (callBack) => { + firebaseAuth().onAuthStateChanged(callBack) + } + } diff --git a/src/data/firebaseClient/services/files/StorageService.ts b/src/data/firebaseClient/services/files/StorageService.ts new file mode 100644 index 00000000..3d90cfd3 --- /dev/null +++ b/src/data/firebaseClient/services/files/StorageService.ts @@ -0,0 +1,41 @@ +import { storageRef } from 'data/firebaseClient' +import { IStorageService } from 'core/services/files' +import { FileResult } from 'models/files/fileResult' + +export class StorageService implements IStorageService { + + /** + * Upload image on the server + * @param {file} file + * @param {string} fileName + */ + public uploadFile = (file: any, fileName: string, progress: (percentage: number, status: boolean) => void) => { + + return new Promise((resolve, reject) => { + // Create a storage refrence + let storegeFile = storageRef.child(`images/${fileName}`) + + // Upload file + let task = storegeFile.put(file) + task.then((result) => { + resolve(new FileResult(result.downloadURL!,result.metadata.fullPath)) + }).catch((error) => { + reject(error) + }) + + // Upload storage bar + task.on('state_changed', (snapshot: any) => { + let percentage: number = (snapshot.bytesTransferred / snapshot.totalBytes) * 100 + progress(percentage, true) + }, (error) => { + console.log('========== Upload Image ============') + console.log(error) + console.log('====================================') + + }, () => { + progress(100, false) + }) + }) + + } +} diff --git a/src/data/firebaseClient/services/files/index.ts b/src/data/firebaseClient/services/files/index.ts new file mode 100644 index 00000000..10a8449c --- /dev/null +++ b/src/data/firebaseClient/services/files/index.ts @@ -0,0 +1,5 @@ +import { StorageService } from './StorageService' + +export { + StorageService +} diff --git a/src/data/firebaseClient/services/imageGallery/ImageGalleryService.ts b/src/data/firebaseClient/services/imageGallery/ImageGalleryService.ts index 9ee7880d..9214cda0 100644 --- a/src/data/firebaseClient/services/imageGallery/ImageGalleryService.ts +++ b/src/data/firebaseClient/services/imageGallery/ImageGalleryService.ts @@ -1,9 +1,12 @@ +import { FileResult } from 'models/files/fileResult' // - Import react components import { firebaseRef, firebaseAuth, storageRef } from 'data/firebaseClient' import { SocialError } from 'core/domain/common' import { IImageGalleryService } from 'core/services/imageGallery' import { Image } from 'core/domain/imageGallery' +import { IStorageService } from 'core/services/files' +import { IServiceProvider, ServiceProvide } from 'core/factories' /** * Firbase image gallery service @@ -14,6 +17,14 @@ import { Image } from 'core/domain/imageGallery' */ export class ImageGalleryService implements IImageGalleryService { + private readonly storageService: IStorageService + private readonly serviceProvider: IServiceProvider + + constructor () { + this.serviceProvider = new ServiceProvide() + this.storageService = this.serviceProvider.createStorageService() + } + public getImageGallery: (userId: string) => Promise = (userId) => { return new Promise((resolve,reject) => { @@ -69,24 +80,15 @@ export class ImageGalleryService implements IImageGalleryService { }) } - public uploadImage: (file: any, fileName: string, progressCallback: Function) - => Promise = (file, fileName, progressCallback) => { - return new Promise((resolve,reject) => { - - let storegeFile = storageRef.child(`images/${fileName}`) - - // Upload file - let task = storegeFile.put(file) - - // Upload storage bar - task.on('state_changed', (snapshot: any) => { - let percentage = (snapshot.bytesTransferred / snapshot.totalBytes) * 100 - progressCallback(percentage) - - }, (error: any) => { + public uploadImage: (image: any, imageName: string, progressCallback: (percentage: number, status: boolean) => void) + => Promise = (image, imageName, progressCallback) => { + return new Promise((resolve,reject) => { + this.storageService.uploadFile(image,imageName,progressCallback) + .then((result: FileResult) => { + resolve(result) + }) + .catch((error: any) => { reject(new SocialError(error.code, error.message)) - }, () => { - resolve() }) }) } diff --git a/src/data/firebaseClient/services/index.ts b/src/data/firebaseClient/services/index.ts index 0dee94ca..f697b257 100644 --- a/src/data/firebaseClient/services/index.ts +++ b/src/data/firebaseClient/services/index.ts @@ -7,6 +7,7 @@ import { NotificationService } from './notifications' import { PostService } from './posts' import { UserService } from './users' import { VoteService } from './votes' +import { StorageService } from './files' export { AuthorizeService, @@ -17,5 +18,7 @@ export { NotificationService, PostService, UserService, - VoteService + VoteService, + StorageService + } diff --git a/src/data/firebaseClient/services/posts/PostService.ts b/src/data/firebaseClient/services/posts/PostService.ts index 3f1f4c94..584e1e92 100644 --- a/src/data/firebaseClient/services/posts/PostService.ts +++ b/src/data/firebaseClient/services/posts/PostService.ts @@ -17,7 +17,7 @@ export class PostService implements IPostService { public addPost: (userId: string, post: Post) => Promise = (userId, post) => { return new Promise((resolve,reject) => { - let postRef: any = firebaseRef.child(`userPosts/${userId}/posts`).push(post) + let postRef: any = firebaseRef.child(`users/${userId}/posts`).push(post) postRef.then(() => { resolve(postRef.key) }) @@ -31,7 +31,7 @@ export class PostService implements IPostService { => Promise = (userId, postId, post) => { return new Promise((resolve,reject) => { let updates: any = {} - updates[`userPosts/${userId}/posts/${postId}`] = post + updates[`users/${userId}/posts/${postId}`] = post firebaseRef.update(updates).then(() => { resolve() }) @@ -45,7 +45,7 @@ export class PostService implements IPostService { => Promise = (userId, postId) => { return new Promise((resolve,reject) => { let updates: any = {} - updates[`userPosts/${userId}/posts/${postId}`] = null + updates[`users/${userId}/posts/${postId}`] = null firebaseRef.update(updates).then(() => { resolve() }) @@ -59,7 +59,7 @@ export class PostService implements IPostService { => Promise<{ [postId: string]: Post }> = (userId) => { return new Promise<{ [postId: string]: Post }>((resolve,reject) => { - let postsRef: any = firebaseRef.child(`userPosts/${userId}/posts`) + let postsRef: any = firebaseRef.child(`users/${userId}/posts`) postsRef.once('value').then((snapshot: any) => { let posts: any = snapshot.val() || {} let parsedPosts: { [postId: string]: Post } = {} @@ -82,7 +82,7 @@ export class PostService implements IPostService { => Promise = (userId, postId) => { return new Promise((resolve,reject) => { - let postsRef: any = firebaseRef.child(`userPosts/${userId}/posts/${postId}`) + let postsRef: any = firebaseRef.child(`users/${userId}/posts/${postId}`) postsRef.once('value').then((snapshot: any) => { let newPost = snapshot.val() || {} diff --git a/src/models/files/fileResult.ts b/src/models/files/fileResult.ts new file mode 100644 index 00000000..b636f432 --- /dev/null +++ b/src/models/files/fileResult.ts @@ -0,0 +1,15 @@ +export class FileResult { + + constructor (private _fileURL: string, private _fileFullPath: string) { + + } + + public get fileURL (): string { + return this._fileURL + } + + public get fileFullPath (): string { + return this._fileFullPath + } + +} \ No newline at end of file diff --git a/src/models/files/index.ts b/src/models/files/index.ts new file mode 100644 index 00000000..d664550a --- /dev/null +++ b/src/models/files/index.ts @@ -0,0 +1 @@ +export { FileResult } from './fileResult' diff --git a/src/tests/actions/authorizeActions.test.jsx b/src/tests/actions/authorizeActions.test.jsx deleted file mode 100644 index de6d3624..00000000 --- a/src/tests/actions/authorizeActions.test.jsx +++ /dev/null @@ -1,34 +0,0 @@ -// - Import react components -import configureMockStore from 'redux-mock-store' -import thunk from 'redux-thunk' -let expect = require('expect') - -import firebase, {firebaseRef} from 'src/firebaseClient' -let authorizeActions = require('authorizeActions') -import * as types from 'actionTypes' - -let createMockStore = configureMockStore([thunk]) - -describe('AuthorizeActions', () => { - it('should generate login action', () => { - const uid = 'UID123456' - let action = { - type: types.LOGIN, - authed: true, - uid - } - let res = authorizeActions.login(action.uid) - - expect(res).toEqual(action) - }) - - it('should generate logout action', () => { - let action = { - type: types.LOGOUT - } - let res = authorizeActions.logout() - - expect(res).toEqual(action) - }) - -}) \ No newline at end of file