From 9caafc61b13ee5c9a8faa9c325984b89d8f29c1a Mon Sep 17 00:00:00 2001 From: amalessid Date: Mon, 23 Sep 2024 16:48:03 +0100 Subject: [PATCH 1/7] feat: disable links --- .../shared-links/Components/LinksTable.tsx | 60 ++++++++++++++++--- src/app/utils/api.class.ts | 4 ++ src/domain/dtos/shlink.ts | 1 + src/mappers/shlink-mapper.ts | 1 + 4 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/app/shared-links/Components/LinksTable.tsx b/src/app/shared-links/Components/LinksTable.tsx index e86cd7b..fe80c99 100644 --- a/src/app/shared-links/Components/LinksTable.tsx +++ b/src/app/shared-links/Components/LinksTable.tsx @@ -1,5 +1,7 @@ 'use client'; + import CalendarTodayIcon from '@mui/icons-material/CalendarToday'; +import LinkOffIcon from '@mui/icons-material/LinkOff'; import { Button, Grid, @@ -11,6 +13,7 @@ import { TableHead, TablePagination, TableRow, + Tooltip, } from '@mui/material'; import { useEffect, useState } from 'react'; import React from 'react'; @@ -32,6 +35,22 @@ interface Column { ) => string | React.JSX.Element; } +interface IActionColumn extends Omit { + id: 'action'; + label: React.JSX.Element; + action: (id: string) => void; +} + +const createActionColumn = ( + label: React.JSX.Element, + action: (id: string) => void, +): IActionColumn => ({ + id: 'action', + label, + minWidth: 50, + action, +}); + const columns: readonly Column[] = [ { id: 'name', label: 'Name', minWidth: 100 }, { @@ -62,14 +81,24 @@ export default function LinksTable() { const [page, setPage] = useState(0); const [rowsPerPage, setRowsPerPage] = useState(10); const [addDialog, setAddDialog] = React.useState(); - + const [refetch, setRefetch] = useState(false); const handleChangePage = (_event: unknown, newPage: number) => { setPage(newPage); }; + const handleDeactivate = async (id: string) => { + await apiSharedLink.deactivateLink(id); + setRefetch(true); + }; + + const actionColumn: IActionColumn[] = [ + createActionColumn(, handleDeactivate), + // TODO: Other actions will be added + ]; + useEffect(() => { apiSharedLink.findLinks().then(({ data }) => setLinks(data)); - }, []); + }, [refetch]); const handleChangeRowsPerPage = ( event: React.ChangeEvent, @@ -82,6 +111,8 @@ export default function LinksTable() { setAddDialog(true); }; + const combinedCols = [...columns, ...actionColumn]; + return ( ))} + Actions @@ -121,13 +153,27 @@ export default function LinksTable() { .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) .map((row) => ( - {columns.map((column) => { + {combinedCols.map((column) => { const value = row[column.id]; return ( - - {column.format - ? column.format(value) - : value?.toString()} + + {column.id === 'action' ? ( + + + + ) : column.format ? ( + column.format(value) + ) : ( + value?.toString() + )} ); })} diff --git a/src/app/utils/api.class.ts b/src/app/utils/api.class.ts index 1065411..516d158 100644 --- a/src/app/utils/api.class.ts +++ b/src/app/utils/api.class.ts @@ -42,6 +42,10 @@ export class ApiSHLink extends BaseApi { async createLink(data: object) { return await this.create({ url: `/${EEndpoint.shareLinks}`, data }); } + + async deactivateLink(id: string) { + return await this.delete({ url: `/share-links/${id}/deactivate` }); + } } instance.interceptors.response.use( diff --git a/src/domain/dtos/shlink.ts b/src/domain/dtos/shlink.ts index 35ecea9..5efde21 100644 --- a/src/domain/dtos/shlink.ts +++ b/src/domain/dtos/shlink.ts @@ -143,6 +143,7 @@ export class SHLinkMiniDto { passwordRequired?: boolean; name: string; url: string; + active: boolean; } /** diff --git a/src/mappers/shlink-mapper.ts b/src/mappers/shlink-mapper.ts index 2a70bd2..b9f7bca 100644 --- a/src/mappers/shlink-mapper.ts +++ b/src/mappers/shlink-mapper.ts @@ -68,6 +68,7 @@ export const mapModelToMiniDto = ( expiryDate: shlinkModel.getConfigExp(), passwordRequired: !!shlinkModel.getConfigPasscode(), url: encodeSHLink(shlinkModel), + active: shlinkModel.getActive(), files: files?.map((x) => { return { location: `${EXTERNAL_URL}/api/v1/share-links/${shlinkModel.getId()}/endpoints/${x.getId()}?ticket=${ticket}`, From aaeec95a4293e6907f5d77ae8647fc78bc5f8252 Mon Sep 17 00:00:00 2001 From: amalessid Date: Tue, 24 Sep 2024 15:17:15 +0100 Subject: [PATCH 2/7] add deactivate confirmation dialog --- .../shared-links/Components/LinksTable.tsx | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/app/shared-links/Components/LinksTable.tsx b/src/app/shared-links/Components/LinksTable.tsx index fe80c99..ceeac6b 100644 --- a/src/app/shared-links/Components/LinksTable.tsx +++ b/src/app/shared-links/Components/LinksTable.tsx @@ -14,6 +14,11 @@ import { TablePagination, TableRow, Tooltip, + Dialog, + DialogActions, + DialogContent, + DialogContentText, + DialogTitle, } from '@mui/material'; import { useEffect, useState } from 'react'; import React from 'react'; @@ -24,6 +29,7 @@ import { SHLinkMiniDto } from '@/domain/dtos/shlink'; import { AddLinkDialog } from './AddLinkDialog'; import BooleanIcon from './BooleanIcon'; +import ConfirmationDialog from './ConfirmationDialog'; interface Column { id: keyof SHLinkMiniDto; @@ -82,13 +88,25 @@ export default function LinksTable() { const [rowsPerPage, setRowsPerPage] = useState(10); const [addDialog, setAddDialog] = React.useState(); const [refetch, setRefetch] = useState(false); + + const [confirmDialogOpen, setConfirmDialogOpen] = useState(false); + const [selectedLinkId, setSelectedLinkId] = useState(null); + const handleChangePage = (_event: unknown, newPage: number) => { setPage(newPage); }; const handleDeactivate = async (id: string) => { - await apiSharedLink.deactivateLink(id); - setRefetch(true); + setSelectedLinkId(id); + setConfirmDialogOpen(true); + }; + + const confirmDeactivate = async () => { + if (selectedLinkId) { + await apiSharedLink.deactivateLink(selectedLinkId); + setRefetch(true); + setConfirmDialogOpen(false); + } }; const actionColumn: IActionColumn[] = [ @@ -191,6 +209,12 @@ export default function LinksTable() { onPageChange={handleChangePage} onRowsPerPageChange={handleChangeRowsPerPage} /> + + ); } From a6f0d741093a8bc8afbb2718210086a18dc74538 Mon Sep 17 00:00:00 2001 From: amalessid Date: Tue, 24 Sep 2024 15:18:21 +0100 Subject: [PATCH 3/7] add deactivate confirmation dialog --- .../Components/ConfirmationDialog.tsx | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/app/shared-links/Components/ConfirmationDialog.tsx diff --git a/src/app/shared-links/Components/ConfirmationDialog.tsx b/src/app/shared-links/Components/ConfirmationDialog.tsx new file mode 100644 index 0000000..051862c --- /dev/null +++ b/src/app/shared-links/Components/ConfirmationDialog.tsx @@ -0,0 +1,41 @@ +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogContentText, + DialogTitle, +} from '@mui/material'; + +export const ConfirmationDialog = ({ + confirmDeactivate, + confirmDialogOpen, + setConfirmDialogOpen, +}: { + confirmDeactivate: () => void; + confirmDialogOpen: boolean; + setConfirmDialogOpen: (arg: boolean) => void; +}) => { + return ( + setConfirmDialogOpen(false)} + > + Confirm Deactivation + + + Are you sure you want to deactivate this link? Deactivating will + permanently disable the link, and you will need to create a new one. + + + + + + + + ); +}; + +export default ConfirmationDialog; From 48aa69dd8583619106bb6593ac83beafe5dc9161 Mon Sep 17 00:00:00 2001 From: amalessid Date: Wed, 25 Sep 2024 14:12:58 +0100 Subject: [PATCH 4/7] wrap button inside span --- src/app/shared-links/Components/LinksTable.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/app/shared-links/Components/LinksTable.tsx b/src/app/shared-links/Components/LinksTable.tsx index ceeac6b..7b09c95 100644 --- a/src/app/shared-links/Components/LinksTable.tsx +++ b/src/app/shared-links/Components/LinksTable.tsx @@ -180,12 +180,14 @@ export default function LinksTable() { > {column.id === 'action' ? ( - + + + ) : column.format ? ( column.format(value) From febf0f788d7f2efcd7db6cfbe66436a9d3e3e058 Mon Sep 17 00:00:00 2001 From: amalessid Date: Wed, 25 Sep 2024 14:30:05 +0100 Subject: [PATCH 5/7] address PR review --- .../shared-links/Components/LinksTable.tsx | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/app/shared-links/Components/LinksTable.tsx b/src/app/shared-links/Components/LinksTable.tsx index 24cf676..1bb54be 100644 --- a/src/app/shared-links/Components/LinksTable.tsx +++ b/src/app/shared-links/Components/LinksTable.tsx @@ -101,9 +101,13 @@ export default function LinksTable() { const confirmDeactivate = async () => { if (selectedLinkId) { - await apiSharedLink.deactivateLink(selectedLinkId); - setRefetch(true); - setConfirmDialogOpen(false); + try { + await apiSharedLink.deactivateLink(selectedLinkId); + setRefetch(true); + setConfirmDialogOpen(false); + } catch (error) { + console.error('Failed to deactivate link:', error); + } } }; @@ -112,9 +116,14 @@ export default function LinksTable() { // TODO: Other actions will be added ]; + const fetchLinks = async () => { + const { data } = await apiSharedLink.findLinks(); + setLinks(data); + }; + useEffect(() => { - apiSharedLink.findLinks().then(({ data }) => setLinks(data)); - }, [refetch]); + fetchLinks(); + }, []); const handleChangeRowsPerPage = ( event: React.ChangeEvent, From d204c9e78f44e2be664a567694d7a757fa9f79a1 Mon Sep 17 00:00:00 2001 From: amalessid Date: Wed, 25 Sep 2024 14:31:54 +0100 Subject: [PATCH 6/7] address PR review --- src/app/shared-links/Components/LinksTable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shared-links/Components/LinksTable.tsx b/src/app/shared-links/Components/LinksTable.tsx index 1bb54be..b753b43 100644 --- a/src/app/shared-links/Components/LinksTable.tsx +++ b/src/app/shared-links/Components/LinksTable.tsx @@ -123,7 +123,7 @@ export default function LinksTable() { useEffect(() => { fetchLinks(); - }, []); + }, [refetch]); const handleChangeRowsPerPage = ( event: React.ChangeEvent, From 8b4748925dc690b69e7b6ccc8b758e4e66ba1097 Mon Sep 17 00:00:00 2001 From: amalessid Date: Wed, 25 Sep 2024 14:53:42 +0100 Subject: [PATCH 7/7] fix bug --- src/app/shared-links/Components/LinksTable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shared-links/Components/LinksTable.tsx b/src/app/shared-links/Components/LinksTable.tsx index b753b43..0967e2f 100644 --- a/src/app/shared-links/Components/LinksTable.tsx +++ b/src/app/shared-links/Components/LinksTable.tsx @@ -103,7 +103,7 @@ export default function LinksTable() { if (selectedLinkId) { try { await apiSharedLink.deactivateLink(selectedLinkId); - setRefetch(true); + setRefetch(!refetch); setConfirmDialogOpen(false); } catch (error) { console.error('Failed to deactivate link:', error);