From 600414164880e06763c50e83ddd7d4f298be73b7 Mon Sep 17 00:00:00 2001 From: Tommi Lepola Date: Fri, 20 Dec 2019 18:39:50 +0200 Subject: [PATCH] Implement possibility to delete users own images --- components/galleryImage/GalleryImage.tsx | 2 +- models/Image.ts | 2 +- store/actions/imagesActions.tsx | 60 ++++++++++++++++++++---- store/actions/userActions.tsx | 7 ++- store/reducers/imagesReducer.tsx | 16 +++---- views/image/Image.tsx | 24 ++++++++-- 6 files changed, 84 insertions(+), 27 deletions(-) diff --git a/components/galleryImage/GalleryImage.tsx b/components/galleryImage/GalleryImage.tsx index 11c15ec..5d1ebad 100644 --- a/components/galleryImage/GalleryImage.tsx +++ b/components/galleryImage/GalleryImage.tsx @@ -37,7 +37,7 @@ const GalleryImage: React.FC = (props: Props) => { }, [imageInView]) const setImageToView = () => { - dispatch(loadImage(image, user?.token)); + dispatch(loadImage(image, user && user.token ? user.token : undefined)); } return ( diff --git a/models/Image.ts b/models/Image.ts index 4c067af..ba25874 100644 --- a/models/Image.ts +++ b/models/Image.ts @@ -3,7 +3,7 @@ import { Comment } from "./Comment"; export interface Image { name: string; description: string; - canDelete: boolean; + userCanDelete: boolean; author: string; comments: Comment[]; score: number; diff --git a/store/actions/imagesActions.tsx b/store/actions/imagesActions.tsx index dfe369a..e9afe06 100644 --- a/store/actions/imagesActions.tsx +++ b/store/actions/imagesActions.tsx @@ -21,6 +21,9 @@ export enum ImagesActionTypes { UploadImage = '[Images] Upload Image', SetUploadSuccess = '[Images] Upload Success', + RemoveImage = '[Images] Remove Image', + RemoveImageSuccess = '[Images] Remove Image Success', + SendComment = '[Images] Send Comment', AddComment = '[Images] Add Comment', RemoveComment = '[Images] Remove Comment', @@ -37,6 +40,15 @@ interface SetImagesAction { payload: Image[]; } +interface RemoveImageAction { + type: ImagesActionTypes.RemoveImage, +} + +interface RemoveImageSuccessAction { + type: ImagesActionTypes.RemoveImageSuccess, + payload: Image; +} + interface LoadUserImagesAction { type: ImagesActionTypes.LoadUserImages; } @@ -71,7 +83,7 @@ interface UploadImageAction { interface SetUploadSuccessAction { type: ImagesActionTypes.SetUploadSuccess; - payload: { success?: boolean, image?: Image }; + payload: { success?: boolean }; } interface SendCommentAction { @@ -97,14 +109,14 @@ const refreshImages = (state: boolean) => { type: ImagesActionTypes.RefreshImages, payload: state, } -} +}; const refreshUserImages = (state: boolean) => { return { type: ImagesActionTypes.RefreshUserImages, payload: state, } -} +}; const setImages = (images: Image[]) => { return { @@ -125,7 +137,7 @@ const removeComment = (comment: Comment) => { type: ImagesActionTypes.RemoveComment, payload: { comment: comment } } -} +}; const setImageToView = (image: Image) => { return { @@ -134,18 +146,25 @@ const setImageToView = (image: Image) => { } }; -const uploadSuccess = (success: boolean, image: Image) => { +const uploadSuccess = (success: boolean) => { return { type: ImagesActionTypes.SetUploadSuccess, - payload: { success: success, image: image }, + payload: { success: success }, } -} +}; -export const setUserImages = (images: Image[]) => { +const setUserImages = (images: Image[]) => { return { type: ImagesActionTypes.SetUserImages, payload: images, } +}; + +const removeImageSuccess = (image: Image) => { + return { + type: ImagesActionTypes.RemoveImageSuccess, + payload: image, + } } export const loadImages = ( @@ -203,7 +222,9 @@ export const uploadImage = ( }, }); - dispatch(uploadSuccess(true, image.data as Image)); + dispatch(loadUserImages(token)); + dispatch(loadImages(token)); + dispatch(uploadSuccess(true)); } catch (err) { console.log(err); } @@ -275,4 +296,23 @@ export const loadImage = ( } } -export type ImagesActions = LoadImagesAction | SetImagesAction | SetUserImagesAction | SetImageInViewAction | SetUploadSuccessAction | RefreshUserImagesAction | RefreshImagesAction | AddCommentAction | RemoveCommentAction; \ No newline at end of file +export const deleteImage = ( + image: Image, token: string +): ThunkAction, {}, {}, RemoveImageAction> => { + return async( + dispatch: ThunkDispatch<{}, {}, RemoveImageSuccessAction> + ): Promise => { + try { + await api.delete(`/image/${token}/${image.id}`); + dispatch(removeImageSuccess(image)); + } catch (err) { + console.log(err); + } + } +} + +export type ImagesActions = + LoadImagesAction | SetImagesAction | SetUserImagesAction | + SetImageInViewAction | SetUploadSuccessAction | RefreshUserImagesAction | + RefreshImagesAction | AddCommentAction | RemoveCommentAction | + RemoveImageSuccessAction; \ No newline at end of file diff --git a/store/actions/userActions.tsx b/store/actions/userActions.tsx index 3cf0640..b62d642 100644 --- a/store/actions/userActions.tsx +++ b/store/actions/userActions.tsx @@ -2,7 +2,7 @@ import { ThunkAction, ThunkDispatch } from "redux-thunk"; import { api } from "../../utils"; import { User } from "../../models"; import { AnyAction } from "redux"; -import { setUserImages } from "../actions/imagesActions"; +import { ImagesActionTypes } from "../actions/imagesActions"; export enum UserActionTypes { SetUser = '[User] Set User', @@ -54,7 +54,10 @@ export const logoutUser = (): ThunkAction, {}, {}, LogoutAction> = return async( dispatch: ThunkDispatch<{}, {}, AnyAction> ): Promise => { - dispatch(setUserImages([])); + dispatch({ + type: ImagesActionTypes.SetUserImages, + payload: [], + }); dispatch(setUser(undefined)); } } diff --git a/store/reducers/imagesReducer.tsx b/store/reducers/imagesReducer.tsx index 7f2e4e1..be3bcbc 100644 --- a/store/reducers/imagesReducer.tsx +++ b/store/reducers/imagesReducer.tsx @@ -79,14 +79,14 @@ export const imagesReducer: Reducer = (state: Images return { ...state, uploadSuccess: action.payload.success, - images: [ - ...state.images, - action.payload.image - ], - userImages: [ - ...state.userImages, - action.payload.image - ] + } + + case ImagesActionTypes.RemoveImageSuccess: + return { + ...state, + imageInView: undefined, + images: state.images.filter(img => img.id !== action.payload.id), + userImages: state.userImages.filter(img => img.id !== action.payload.id) } default: diff --git a/views/image/Image.tsx b/views/image/Image.tsx index 115b1b7..194c428 100644 --- a/views/image/Image.tsx +++ b/views/image/Image.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { Entypo as EntypoIcon, MaterialIcons as MaterialIcon, Ionicons as IonIcon } from '@expo/vector-icons'; import { Image, SafeAreaView, Text, View, ScrollView, TextInput, TouchableOpacity, Platform } from 'react-native'; @@ -13,11 +13,13 @@ import { Image as ImageModel, Comment } from '../../models'; import ImageComment from '../../components/comment/Comment'; import Header from '../../components/header/Header'; -import { sendComment, voteImage } from '../../store/actions/imagesActions'; +import { sendComment, voteImage, deleteImage } from '../../store/actions/imagesActions'; import { selectUser } from '../../store/reducers/userReducer'; import { selectImageInView } from '../../store/reducers/imagesReducer'; -const ImageView: NavigationStackScreenComponent = () => { +const ImageView: NavigationStackScreenComponent = (props) => { + const { navigation } = props; + const dispatch = useDispatch(); const user = useSelector(selectUser); const keyboardHeight = useSelector(selectKeyboardHeight); @@ -31,6 +33,12 @@ const ImageView: NavigationStackScreenComponent = () => { ? 'ios-send' : 'md-send'; + useEffect(() => { + if (!image) { + navigation.pop(); + } + }, [image]) + const addComment = () => { if (!user || !user.token) { return; } @@ -47,6 +55,12 @@ const ImageView: NavigationStackScreenComponent = () => { dispatch(voteImage(user.token, image, upVote, upVote && image.userUpVoted || !upVote && image.userDownVoted)); } + const removeImage = () => { + if (!user || !user.token) { return; } + + dispatch(deleteImage(image, user.token)); + } + return !image ? null : ( @@ -67,8 +81,8 @@ const ImageView: NavigationStackScreenComponent = () => { - { !image.canDelete ? undefined : - addVote(false)}> + { !image.userCanDelete ? undefined : + removeImage()}> }