From 1ac29592b8a3e788f20c2434958687a016fb398e Mon Sep 17 00:00:00 2001 From: Ahtisham992 Date: Tue, 21 Jul 2026 15:49:33 +0500 Subject: [PATCH 1/3] fix(client): handle joining a deleted channel gracefully --- .../components/ChatContainer/ChatHeader.tsx | 19 ++++++++++++-- .../components/SetupOverlay/SetupOverlay.tsx | 21 +++++++++++++--- client/src/components/common/icons.tsx | 17 +++++++++++++ client/src/context/ChatContext.tsx | 25 +++++++++++++++++++ client/src/types/index.ts | 1 + 5 files changed, 78 insertions(+), 5 deletions(-) diff --git a/client/src/components/ChatContainer/ChatHeader.tsx b/client/src/components/ChatContainer/ChatHeader.tsx index 43a8b3b..d6fe068 100644 --- a/client/src/components/ChatContainer/ChatHeader.tsx +++ b/client/src/components/ChatContainer/ChatHeader.tsx @@ -5,7 +5,7 @@ import React, { useState } from 'react'; import { useChat } from '../../context/ChatContext'; import { Button } from '../common/Button'; -import { CopyIcon, ShareIcon, PhoneIcon } from '../common/icons'; +import { CopyIcon, ShareIcon, PhoneIcon, TrashIcon } from '../common/icons'; import './ChatHeader.css'; interface ChatHeaderProps { @@ -13,7 +13,7 @@ interface ChatHeaderProps { } export const ChatHeader: React.FC = ({ onStartCall }) => { - const { isConnected, channelHash } = useChat(); + const { isConnected, channelHash, deleteChannel } = useChat(); const [hashCopied, setHashCopied] = useState(false); const handleCopyHash = () => { @@ -36,6 +36,13 @@ export const ChatHeader: React.FC = ({ onStartCall }) => { } }; + const handleDelete = async () => { + if (window.confirm('Are you sure you want to delete this secure channel? This cannot be undone.')) { + await deleteChannel(); + window.location.hash = ''; // Clear URL hash + } + }; + return (
@@ -81,6 +88,14 @@ export const ChatHeader: React.FC = ({ onStartCall }) => { > +
); diff --git a/client/src/components/SetupOverlay/SetupOverlay.tsx b/client/src/components/SetupOverlay/SetupOverlay.tsx index cff469f..89dc2a0 100644 --- a/client/src/components/SetupOverlay/SetupOverlay.tsx +++ b/client/src/components/SetupOverlay/SetupOverlay.tsx @@ -14,7 +14,7 @@ interface SetupOverlayProps { isHidden: boolean; } -type ViewType = 'initial' | 'create' | 'join'; +type ViewType = 'initial' | 'create' | 'join' | 'deleted'; export const SetupOverlay: React.FC = ({ onSetupComplete, isHidden }) => { const { createNewChannel } = useChat(); @@ -88,8 +88,13 @@ export const SetupOverlay: React.FC = ({ onSetupComplete, isH setIsLoading(true); setStatus('Connecting...'); await onSetupComplete(joinHash); - } catch (err) { - setStatus('Failed to join channel. Please check the hash and try again.'); + } catch (err: any) { + if (err.message === 'CHANNEL_DELETED') { + setView('deleted'); + setStatus(''); + } else { + setStatus('Failed to join channel. Please check the hash and try again.'); + } console.error('Join error:', err); } finally { setIsLoading(false); @@ -127,6 +132,16 @@ export const SetupOverlay: React.FC = ({ onSetupComplete, isH /> )} + {view === 'deleted' && ( +
+

Channel Deleted

+

This secure channel has been permanently deleted and can no longer be accessed.

+ +
+ )} + {status &&
{status}
} diff --git a/client/src/components/common/icons.tsx b/client/src/components/common/icons.tsx index c4a6cba..35289fa 100644 --- a/client/src/components/common/icons.tsx +++ b/client/src/components/common/icons.tsx @@ -94,3 +94,20 @@ export const EndCallIcon: React.FC = ({ size = 24, className = '' }) ); + +export const TrashIcon: React.FC = ({ size = 24, className = '' }) => ( + + + + +); diff --git a/client/src/context/ChatContext.tsx b/client/src/context/ChatContext.tsx index 09e4043..f791d20 100644 --- a/client/src/context/ChatContext.tsx +++ b/client/src/context/ChatContext.tsx @@ -57,6 +57,16 @@ export const ChatProvider: React.FC<{ children: ReactNode }> = ({ children }) => async (hash: string) => { if (!chat) throw new Error('Chat not initialized'); try { + // Check for channel status before joining + const baseUrl = process.env.CHATE2EE_API_URL || 'http://localhost:3001'; + const statusRes = await fetch(`${baseUrl}/chatHash/status/${hash}`); + if (statusRes.status === 404) { + throw new Error('CHANNEL_DELETED'); + } + if (!statusRes.ok) { + throw new Error('Failed to verify channel status'); + } + // Auto-generate User ID const newUserId = (utils as any).generateUUID(); setUserId(newUserId); @@ -181,6 +191,20 @@ export const ChatProvider: React.FC<{ children: ReactNode }> = ({ children }) => } }; + // Delete channel + const deleteChannel = useCallback(async () => { + if (!chat) return; + try { + await chat.delete(); + setIsConnected(false); + setChannelHash(''); + setMessages([]); + } catch (err) { + console.error('Failed to delete channel:', err); + throw err; + } + }, [chat]); + const value: ChatContextType = { chat, userId, @@ -199,6 +223,7 @@ export const ChatProvider: React.FC<{ children: ReactNode }> = ({ children }) => endCall, addMessage, setCallDuration, + deleteChannel, }; return {children}; diff --git a/client/src/types/index.ts b/client/src/types/index.ts index 8380d01..b908d06 100644 --- a/client/src/types/index.ts +++ b/client/src/types/index.ts @@ -49,6 +49,7 @@ export interface ChatContextType { endCall: () => Promise; addMessage: (message: Message) => void; setCallDuration: (duration: number) => void; + deleteChannel: () => Promise; } // Common component props From f4857820d3c095951423297916a44f88b7675e4d Mon Sep 17 00:00:00 2001 From: Ahtisham992 Date: Tue, 21 Jul 2026 16:01:23 +0500 Subject: [PATCH 2/3] fix: address copilot review comments --- backend/api/chatHash/index.ts | 9 ++++++--- client/src/components/ChatContainer/ChatHeader.tsx | 1 + client/src/context/ChatContext.tsx | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/backend/api/chatHash/index.ts b/backend/api/chatHash/index.ts index 5b63feb..4f541d9 100644 --- a/backend/api/chatHash/index.ts +++ b/backend/api/chatHash/index.ts @@ -50,13 +50,16 @@ router.get( "/status/:channel", asyncHandler(async (req, res) => { const { channel } = req.params; - const { valid } = await channelValid(channel); + const { valid, state } = await channelValid(channel); if (!valid) { - return res.sendStatus(404).send("Invalid channel"); + if (state === CHANNEL_STATE.DELETED) { + return res.status(410).send({ error: "Channel deleted", state }); + } + return res.status(404).send({ error: "Invalid channel", state }); } - return res.send({ status: "ok" }); + return res.send({ status: "ok", state }); }) ); router.delete( diff --git a/client/src/components/ChatContainer/ChatHeader.tsx b/client/src/components/ChatContainer/ChatHeader.tsx index d6fe068..364cbe1 100644 --- a/client/src/components/ChatContainer/ChatHeader.tsx +++ b/client/src/components/ChatContainer/ChatHeader.tsx @@ -93,6 +93,7 @@ export const ChatHeader: React.FC = ({ onStartCall }) => { variant="danger" onClick={handleDelete} title="Delete Chat" + disabled={!channelHash} > diff --git a/client/src/context/ChatContext.tsx b/client/src/context/ChatContext.tsx index f791d20..bb06da4 100644 --- a/client/src/context/ChatContext.tsx +++ b/client/src/context/ChatContext.tsx @@ -59,8 +59,8 @@ export const ChatProvider: React.FC<{ children: ReactNode }> = ({ children }) => try { // Check for channel status before joining const baseUrl = process.env.CHATE2EE_API_URL || 'http://localhost:3001'; - const statusRes = await fetch(`${baseUrl}/chatHash/status/${hash}`); - if (statusRes.status === 404) { + const statusRes = await fetch(`${baseUrl}/api/chat-link/status/${encodeURIComponent(hash)}`); + if (statusRes.status === 410) { throw new Error('CHANNEL_DELETED'); } if (!statusRes.ok) { From b9766f0214546aa1fedb3b4b299d3be5a977e119 Mon Sep 17 00:00:00 2001 From: Muhammad Ahtisham <121355933+Ahtisham992@users.noreply.github.com> Date: Tue, 21 Jul 2026 18:55:42 +0500 Subject: [PATCH 3/3] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../src/components/ChatContainer/ChatHeader.tsx | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/client/src/components/ChatContainer/ChatHeader.tsx b/client/src/components/ChatContainer/ChatHeader.tsx index 364cbe1..e58ea5b 100644 --- a/client/src/components/ChatContainer/ChatHeader.tsx +++ b/client/src/components/ChatContainer/ChatHeader.tsx @@ -36,12 +36,17 @@ export const ChatHeader: React.FC = ({ onStartCall }) => { } }; - const handleDelete = async () => { - if (window.confirm('Are you sure you want to delete this secure channel? This cannot be undone.')) { - await deleteChannel(); - window.location.hash = ''; // Clear URL hash - } - }; +const handleDelete = async () => { + if (!window.confirm('Are you sure you want to delete this secure channel? This cannot be undone.')) return; + + try { + await deleteChannel(); + window.location.hash = ''; // Clear URL hash + } catch (err) { + console.error('Failed to delete channel:', err); + alert((err as any).message || 'Failed to delete channel'); + } +}; return (