Files
PrivyDrop/frontend/components/ClipboardApp/SendTabPanel.tsx
T

179 lines
6.3 KiB
TypeScript

import React, { useState, useEffect, useCallback } from "react";
import dynamic from "next/dynamic";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import {
ReadClipboardButton,
WriteClipboardButton,
} from "@/components/common/clipboard_btn";
import { FileUploadHandler } from "@/components/ClipboardApp/FileUploadHandler";
import FileListDisplay from "@/components/ClipboardApp/FileListDisplay";
import AnimatedButton from "@/components/ui/AnimatedButton";
import type { Messages } from "@/types/messages";
import type { CustomFile, FileMeta } from "@/types/webrtc";
import type { ProgressState } from "@/hooks/useWebRTCConnection";
import type WebRTC_Initiator from "@/lib/webrtc_Initiator";
// Dynamically import the RichTextEditor
const RichTextEditor = dynamic(
() => import("@/components/Editor/RichTextEditor"),
{
ssr: false, // This component is client-side only
loading: () => (
<div className="p-4 border rounded-lg min-h-[200px] md:min-h-[400px] bg-gray-50 flex items-center justify-center">
Loading Editor...
</div>
),
}
);
interface SendTabPanelProps {
messages: Messages;
shareRoomStatusText: string;
shareContent: string;
sendFiles: CustomFile[];
updateShareContent: (content: string) => void;
addFilesToSend: (files: CustomFile[]) => void;
removeFileToSend: (meta: FileMeta) => void;
richTextToPlainText: (html: string) => string;
sendProgress: ProgressState;
isAnyFileTransferring: boolean;
// shareRoomId: string; // This comes from useRoomManager and represents the validated ID
processRoomIdInput: (roomId: string) => void; // Passed from useRoomManager
joinRoom: (isSender: boolean, roomId: string) => void;
generateShareLinkAndBroadcast: () => void;
sender: WebRTC_Initiator | null;
shareMessage: string;
// Pass the validated/initial shareRoomId from useRoomManager for display/initialization
// Also, initShareRoomId can be useful if we want to reset the input to it.
currentValidatedShareRoomId: string;
handleLeaveSenderRoom: () => void; // New prop for leaving room
// initShareRoomId: string; // If needed for reset logic
}
export function SendTabPanel({
messages,
shareRoomStatusText,
shareContent,
sendFiles,
updateShareContent,
addFilesToSend,
removeFileToSend,
richTextToPlainText,
sendProgress,
isAnyFileTransferring,
processRoomIdInput,
joinRoom,
generateShareLinkAndBroadcast,
sender,
shareMessage,
currentValidatedShareRoomId,
handleLeaveSenderRoom,
}: // initShareRoomId,
SendTabPanelProps) {
// Local state for immediate response in the input field
const [inputFieldValue, setInputFieldValue] = useState<string>(
currentValidatedShareRoomId
);
// When the validatedShareRoomId from the parent component changes (e.g., after initial fetch), synchronize the local input field's value
useEffect(() => {
setInputFieldValue(currentValidatedShareRoomId);
}, [currentValidatedShareRoomId]);
const handleInputChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
const newValue = e.target.value;
setInputFieldValue(newValue); // Immediately update the input field display
processRoomIdInput(newValue); // Call the handler function from the hook, which will perform debounced validation
},
[processRoomIdInput]
);
const handlePaste = useCallback(
(e: React.ClipboardEvent<HTMLInputElement>) => {
const pastedText = e.clipboardData.getData("text").trim();
setInputFieldValue(pastedText);
processRoomIdInput(pastedText);
},
[processRoomIdInput]
);
return (
<div id="send-panel" role="tabpanel" aria-labelledby="send-tab">
<div className="mb-3 text-sm text-gray-600">
{shareRoomStatusText ||
(sender?.isInRoom
? messages.text.ClipboardApp.roomStatus.onlyOneMsg
: messages.text.ClipboardApp.roomStatus.senderEmptyMsg)}
</div>
<RichTextEditor value={shareContent} onChange={updateShareContent} />
<div className="flex flex-wrap gap-2 my-3">
<ReadClipboardButton
title={messages.text.ClipboardApp.html.Paste_dis}
onRead={updateShareContent}
/>
<WriteClipboardButton
title={messages.text.ClipboardApp.html.Copy_dis}
textToCopy={richTextToPlainText(shareContent)}
/>
</div>
<div className="mb-3">
<FileUploadHandler onFilePicked={addFilesToSend} />
<FileListDisplay
mode="sender"
files={sendFiles}
fileProgresses={sendProgress}
isAnyFileTransferring={isAnyFileTransferring}
onDelete={removeFileToSend}
/>
</div>
<div className="flex flex-col sm:flex-row items-center gap-2 mb-3">
<span className="text-sm whitespace-nowrap">
{messages.text.ClipboardApp.html.inputRoomId_tips}
</span>
<Input
aria-label="Share Room ID"
value={inputFieldValue} // Bind to local state
onChange={handleInputChange}
onPaste={handlePaste}
className="flex-grow min-w-0"
/>
<Button
className="w-full sm:w-auto"
onClick={() => joinRoom(true, inputFieldValue.trim())} // Attempt to join using the current input field value
disabled={!sender || sender.isInRoom || !inputFieldValue.trim()}
>
{messages.text.ClipboardApp.html.joinRoom_dis}
</Button>
</div>
<div className="flex gap-2">
<AnimatedButton
className="flex-1"
onClick={generateShareLinkAndBroadcast}
loadingText={messages.text.ClipboardApp.html.SyncSending_loadingText}
disabled={
!sender ||
!sender.isInRoom ||
(sendFiles.length === 0 && shareContent.trim() === "") ||
!currentValidatedShareRoomId.trim() ||
isAnyFileTransferring
} // Ensure there is a validated room ID before allowing sharing
>
{messages.text.ClipboardApp.html.SyncSending_dis}
</AnimatedButton>
<Button
variant="outline"
onClick={handleLeaveSenderRoom}
disabled={!sender || !sender.isInRoom || isAnyFileTransferring}
>
Leave Room
</Button>
</div>
{shareMessage && (
<p className="mt-3 text-sm text-blue-600">{shareMessage}</p>
)}
</div>
);
}