From 20ddede04ef6a8979fbd5ce832fc3b2714da0332 Mon Sep 17 00:00:00 2001 From: overflowerror Date: Sun, 22 Aug 2021 17:30:26 +0200 Subject: [PATCH] feat: deleting threads now works --- backend/internal/app/data.go | 1 + backend/internal/app/logic.go | 2 + backend/internal/data/thread.go | 4 + backend/internal/logic/thread.go | 4 + backend/internal/presentation/thread.go | 14 ++++ backend/internal/router/routes.go | 1 + frontend/src/api/endpoints/ThreadEndpoint.ts | 4 + frontend/src/components/AccountCard/index.tsx | 4 + frontend/src/components/ThreadList/index.tsx | 78 ++++++++++++++++++- 9 files changed, 108 insertions(+), 4 deletions(-) diff --git a/backend/internal/app/data.go b/backend/internal/app/data.go index bc356b2..0b9ea5c 100644 --- a/backend/internal/app/data.go +++ b/backend/internal/app/data.go @@ -28,6 +28,7 @@ type Data interface { AddThread(thread *models.Thread) error UpdateThread(thread *models.Thread) error + DeleteThread(id uuid.UUID) error GetThread(id uuid.UUID, user *models.User) (*models.Thread, error) GetThreads(user *models.User) ([]models.Thread, error) GetScheduledThreads() ([]models.Thread, error) diff --git a/backend/internal/app/logic.go b/backend/internal/app/logic.go index 7f1995f..95df8f4 100644 --- a/backend/internal/app/logic.go +++ b/backend/internal/app/logic.go @@ -1,6 +1,7 @@ package app import ( + uuid "github.com/satori/go.uuid" "net/url" "threadule/backend/internal/data/models" ) @@ -15,5 +16,6 @@ type Logic interface { AddThread(thread *models.Thread, user *models.User) error UpdateThread(thread *models.Thread, user *models.User) error + DeleteThread(id uuid.UUID) error GetThreads(user *models.User) ([]models.Thread, error) } diff --git a/backend/internal/data/thread.go b/backend/internal/data/thread.go index 97a5d35..53a79f0 100644 --- a/backend/internal/data/thread.go +++ b/backend/internal/data/thread.go @@ -31,6 +31,10 @@ func (d *Data) UpdateThreadWithoutTweets(thread *models.Thread) error { Error } +func (d *Data) DeleteThread(id uuid.UUID) error { + return d.db.Delete(&models.Thread{}, id).Error +} + func (d *Data) GetThread(id uuid.UUID, user *models.User) (*models.Thread, error) { var thread models.Thread err := d.db. diff --git a/backend/internal/logic/thread.go b/backend/internal/logic/thread.go index 3b7fb6f..2984ff6 100644 --- a/backend/internal/logic/thread.go +++ b/backend/internal/logic/thread.go @@ -46,6 +46,10 @@ func (l *Logic) UpdateThread(thread *models.Thread, user *models.User) error { return err } +func (l *Logic) DeleteThread(id uuid.UUID) error { + return l.ctx.Data.DeleteThread(id) +} + func (l *Logic) GetThreads(user *models.User) ([]models.Thread, error) { return l.ctx.Data.GetThreads(user) } diff --git a/backend/internal/presentation/thread.go b/backend/internal/presentation/thread.go index 37e1f29..762cb08 100644 --- a/backend/internal/presentation/thread.go +++ b/backend/internal/presentation/thread.go @@ -54,6 +54,20 @@ func UpdateThread(ctx *web.Context) { } } +func DeleteThread(ctx *web.Context) { + id, err := uuid.FromString(ctx.Params.ByName("id")) + if err != nil { + ErrorResponse(ctx, err) + return + } + + err = ctx.AppCtx.Logic.DeleteThread(id) + if err != nil { + ErrorResponse(ctx, err) + return + } +} + func GetThreads(ctx *web.Context) { threads, err := ctx.AppCtx.Logic.GetThreads(ctx.Session.User) if err != nil { diff --git a/backend/internal/router/routes.go b/backend/internal/router/routes.go index e0f8cb9..4ebe4de 100644 --- a/backend/internal/router/routes.go +++ b/backend/internal/router/routes.go @@ -30,6 +30,7 @@ func Setup(ctx *app.Context) http.Handler { router.GET("/thread", authenticated(GetThreads)) router.POST("/thread/", authenticated(AddThread)) router.PUT("/thread/:id", authenticated(UpdateThread)) + router.DELETE("/thread/:id", authenticated(DeleteThread)) return router } diff --git a/frontend/src/api/endpoints/ThreadEndpoint.ts b/frontend/src/api/endpoints/ThreadEndpoint.ts index e8b48c8..c7a2fc7 100644 --- a/frontend/src/api/endpoints/ThreadEndpoint.ts +++ b/frontend/src/api/endpoints/ThreadEndpoint.ts @@ -17,6 +17,10 @@ class ThreadEndpoint extends Endpoint { public async update(thread: Thread): Promise { return await this.put(API_PREFIX + thread.id, thread) } + + public async remove(thread: Thread): Promise { + return await this.delete(API_PREFIX + thread.id) + } } export default ThreadEndpoint \ No newline at end of file diff --git a/frontend/src/components/AccountCard/index.tsx b/frontend/src/components/AccountCard/index.tsx index e9de0b5..ad36c95 100644 --- a/frontend/src/components/AccountCard/index.tsx +++ b/frontend/src/components/AccountCard/index.tsx @@ -82,6 +82,10 @@ const AccountCard: FunctionComponent = ( { + account.threads = account.threads.filter(t => t.id != thread.id) + onUpdate(account) + }} /> diff --git a/frontend/src/components/ThreadList/index.tsx b/frontend/src/components/ThreadList/index.tsx index 21d788b..2840f59 100644 --- a/frontend/src/components/ThreadList/index.tsx +++ b/frontend/src/components/ThreadList/index.tsx @@ -1,16 +1,73 @@ -import {FunctionComponent} from "react"; -import {Avatar, List, ListItem, ListItemAvatar, ListItemText, Typography} from "@material-ui/core"; +import {FunctionComponent, useState} from "react"; +import { + Avatar, + IconButton, + List, + ListItem, + ListItemAvatar, + ListItemSecondaryAction, + ListItemText, + Typography +} from "@material-ui/core"; import Thread from "../../api/entities/Thread"; import CustomDate from "../../utils/CustomDate"; import styles from "./ThreadList.module.css" +import DeleteIcon from "@material-ui/icons/Delete"; +import {useAuth} from "../../auth/AuthProvider"; +import ThreadEndpoint from "../../api/endpoints/ThreadEndpoint"; +import {MessageBox, MessageBoxProps} from "../MessageBox"; export type ThreadListProps = { threads: Thread[] onSelect: (thread: Thread) => void + onDelete: (thread: Thread) => void } -const ThreadList: FunctionComponent = ({threads, onSelect}) => { + +const ThreadList: FunctionComponent = ( + { + threads, + onSelect, + onDelete + } +) => { + const {client} = useAuth() + + const [message, setMessage] = useState({ + open: false, + success: false, + message: "", + onClose: () => { + setMessage({ + ...message, + open: false, + }) + } + }) + + const deleteThread = (thread: Thread) => { + new ThreadEndpoint(client).remove(thread) + .then(() => { + onDelete(thread) + setMessage({ + ...message, + open: true, + success: true, + message: "Thread was deleted successfully." + }) + }) + .catch((errors) => { + console.error(errors) + setMessage({ + ...message, + open: true, + success: false, + message: "Thread couldn't be deleted." + }) + }) + } + if (threads.length == 0) { return ( = ({threads, onSelect}) => ) } else { return ( + <> {threads.map(thread => { return ( @@ -38,11 +96,23 @@ const ThreadList: FunctionComponent = ({threads, onSelect}) => {thread.tweets[0].text}} - secondary={new CustomDate(thread.scheduled_for).toLocalISOString(false, true)}/> + secondary={new CustomDate(thread.scheduled_for).toLocalISOString(false, true)} + /> + + deleteThread(thread)} + > + + + ) })} + + ) } }