chore(code):Add cache room ID feature, no need to manually input room ID
This commit is contained in:
@@ -202,6 +202,7 @@ const ClipboardApp = () => {
|
||||
shareMessage={shareMessage}
|
||||
currentValidatedShareRoomId={shareRoomId}
|
||||
handleLeaveSenderRoom={handleLeaveSenderRoom}
|
||||
putMessageInMs={putMessageInMs}
|
||||
/>
|
||||
) : (
|
||||
<RetrieveTabPanel
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import React, { useCallback } from "react";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
ReadClipboardButton,
|
||||
WriteClipboardButton,
|
||||
} from "@/components/common/clipboard_btn";
|
||||
import Tooltip from "@/components/Tooltip";
|
||||
import FileListDisplay from "@/components/ClipboardApp/FileListDisplay";
|
||||
import type { Messages } from "@/types/messages";
|
||||
import type { FileMeta } from "@/types/webrtc";
|
||||
|
||||
import { useFileTransferStore } from "@/stores/fileTransferStore";
|
||||
import { getCachedId, setCachedId } from "@/lib/roomIdCache";
|
||||
|
||||
interface RetrieveTabPanelProps {
|
||||
messages: Messages;
|
||||
@@ -60,6 +62,12 @@ export function RetrieveTabPanel({
|
||||
isReceiverInRoom,
|
||||
} = useFileTransferStore();
|
||||
|
||||
// Cached ID state
|
||||
const [hasCachedId, setHasCachedId] = useState<boolean>(false);
|
||||
useEffect(() => {
|
||||
setHasCachedId(!!getCachedId());
|
||||
}, []);
|
||||
|
||||
const onLocationPick = useCallback(async (): Promise<boolean> => {
|
||||
if (!messages) return false; // Should not happen if panel is rendered
|
||||
if (!window.showDirectoryPicker) {
|
||||
@@ -111,6 +119,46 @@ export function RetrieveTabPanel({
|
||||
title={messages.text.ClipboardApp.html.readClipboard_dis}
|
||||
onRead={setRetrieveRoomIdInput}
|
||||
/>
|
||||
{/* Save/Use Cached ID Button placed after Paste button */}
|
||||
<Tooltip
|
||||
content={
|
||||
hasCachedId
|
||||
? messages.text.ClipboardApp.html.useCachedId_tips
|
||||
: messages.text.ClipboardApp.html.saveId_tips
|
||||
}
|
||||
>
|
||||
<span className="inline-block">
|
||||
<Button
|
||||
className="w-full sm:w-auto px-4"
|
||||
variant="outline"
|
||||
onClick={() => {
|
||||
if (hasCachedId) {
|
||||
const cached = getCachedId();
|
||||
if (cached) {
|
||||
setRetrieveRoomIdInput(cached);
|
||||
}
|
||||
} else {
|
||||
const trimmed = retrieveRoomIdInput.trim();
|
||||
if (trimmed.length >= 8) {
|
||||
setCachedId(trimmed);
|
||||
setHasCachedId(true);
|
||||
putMessageInMs(
|
||||
messages.text.ClipboardApp.saveId_success,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
}}
|
||||
disabled={
|
||||
!hasCachedId && retrieveRoomIdInput.trim().length < 8
|
||||
}
|
||||
>
|
||||
{hasCachedId
|
||||
? messages.text.ClipboardApp.html.useCachedId_dis
|
||||
: messages.text.ClipboardApp.html.saveId_dis}
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
<Input
|
||||
aria-label="Retrieve Room ID"
|
||||
value={retrieveRoomIdInput}
|
||||
|
||||
@@ -2,6 +2,7 @@ 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 Tooltip from "@/components/Tooltip";
|
||||
import {
|
||||
ReadClipboardButton,
|
||||
WriteClipboardButton,
|
||||
@@ -13,6 +14,7 @@ import type { Messages } from "@/types/messages";
|
||||
import type { CustomFile, FileMeta } from "@/types/webrtc";
|
||||
|
||||
import { useFileTransferStore } from "@/stores/fileTransferStore";
|
||||
import { getCachedId, setCachedId } from "@/lib/roomIdCache";
|
||||
|
||||
// Dynamically import the RichTextEditor
|
||||
const RichTextEditor = dynamic(
|
||||
@@ -39,6 +41,11 @@ interface SendTabPanelProps {
|
||||
shareMessage: string;
|
||||
currentValidatedShareRoomId: string;
|
||||
handleLeaveSenderRoom: () => void; // New prop for leaving room
|
||||
putMessageInMs: (
|
||||
message: string,
|
||||
isShareEnd?: boolean,
|
||||
displayTimeMs?: number
|
||||
) => void;
|
||||
}
|
||||
|
||||
export function SendTabPanel({
|
||||
@@ -53,6 +60,7 @@ export function SendTabPanel({
|
||||
shareMessage,
|
||||
currentValidatedShareRoomId,
|
||||
handleLeaveSenderRoom,
|
||||
putMessageInMs,
|
||||
}: SendTabPanelProps) {
|
||||
// Get the status from the store
|
||||
const {
|
||||
@@ -69,12 +77,18 @@ export function SendTabPanel({
|
||||
);
|
||||
// State to track ID generation mode (false = will show simple next, true = will show random next)
|
||||
const [isSimpleIdMode, setIsSimpleIdMode] = useState<boolean>(true);
|
||||
// Cached ID state
|
||||
const [hasCachedId, setHasCachedId] = useState<boolean>(false);
|
||||
|
||||
// When the validatedShareRoomId from the parent component changes (e.g., after initial fetch), synchronize the local input field's value
|
||||
useEffect(() => {
|
||||
setInputFieldValue(currentValidatedShareRoomId);
|
||||
}, [currentValidatedShareRoomId]);
|
||||
|
||||
useEffect(() => {
|
||||
setHasCachedId(!!getCachedId());
|
||||
}, []);
|
||||
|
||||
const handleInputChange = useCallback(
|
||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const newValue = e.target.value;
|
||||
@@ -127,6 +141,31 @@ export function SendTabPanel({
|
||||
setIsSimpleIdMode(!isSimpleIdMode);
|
||||
}, [isSimpleIdMode, processRoomIdInput, setInputFieldValue]);
|
||||
|
||||
// Save/Use cached ID button handlers
|
||||
const isSaveEnabled = (inputFieldValue || "").trim().length >= 8;
|
||||
const handleSaveOrUseCachedId = useCallback(() => {
|
||||
if (hasCachedId) {
|
||||
const cached = getCachedId();
|
||||
if (cached) {
|
||||
setInputFieldValue(cached);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Save current input to cache
|
||||
const trimmed = (inputFieldValue || "").trim();
|
||||
if (trimmed.length >= 8) {
|
||||
setCachedId(trimmed);
|
||||
setHasCachedId(true);
|
||||
// Notify via messages on sender side
|
||||
putMessageInMs(messages.text.ClipboardApp.saveId_success, true);
|
||||
}
|
||||
}, [
|
||||
hasCachedId,
|
||||
inputFieldValue,
|
||||
putMessageInMs,
|
||||
messages.text.ClipboardApp.saveId_success,
|
||||
]);
|
||||
|
||||
return (
|
||||
<div id="send-panel" role="tabpanel" aria-labelledby="send-tab">
|
||||
<div className="mb-3 text-sm text-gray-600">
|
||||
@@ -183,6 +222,27 @@ export function SendTabPanel({
|
||||
? messages.text.ClipboardApp.html.generateRandomId_tips
|
||||
: messages.text.ClipboardApp.html.generateSimpleId_tips}
|
||||
</Button>
|
||||
{/* Save/Use Cached ID Button in between */}
|
||||
<Tooltip
|
||||
content={
|
||||
hasCachedId
|
||||
? messages.text.ClipboardApp.html.useCachedId_tips
|
||||
: messages.text.ClipboardApp.html.saveId_tips
|
||||
}
|
||||
>
|
||||
<span className="inline-block">
|
||||
<Button
|
||||
className="w-full sm:w-auto px-4"
|
||||
variant="outline"
|
||||
onClick={handleSaveOrUseCachedId}
|
||||
disabled={!hasCachedId && !isSaveEnabled}
|
||||
>
|
||||
{hasCachedId
|
||||
? messages.text.ClipboardApp.html.useCachedId_dis
|
||||
: messages.text.ClipboardApp.html.saveId_dis}
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
<Button
|
||||
className="w-full sm:w-auto px-4"
|
||||
onClick={() => joinRoom(true, inputFieldValue.trim())}
|
||||
|
||||
@@ -336,7 +336,15 @@ export const de: Messages = {
|
||||
readClipboard_dis: "Raum-ID einfügen",
|
||||
retrieveRoomId_placeholder: "Raum-ID eingeben",
|
||||
RetrieveMethodTitle: "Abrufmethode",
|
||||
// New: cached ID utils
|
||||
saveId_dis: "ID speichern",
|
||||
useCachedId_dis: "Gespeicherte ID verwenden",
|
||||
saveId_tips: "Aktuelle ID für spätere schnelle Nutzung speichern",
|
||||
useCachedId_tips:
|
||||
"Zuvor gespeicherte ID verwenden, um Tippen zu vermeiden",
|
||||
},
|
||||
// New: cache messages
|
||||
saveId_success: "Erfolgreich im Cache gespeichert",
|
||||
},
|
||||
home: {
|
||||
h1: "Kostenloses sicheres Online-Clipboard & Dateiübertragungstool",
|
||||
|
||||
@@ -327,7 +327,15 @@ export const en: Messages = {
|
||||
readClipboard_dis: "Paste RoomID",
|
||||
retrieveRoomId_placeholder: "Enter RoomID",
|
||||
RetrieveMethodTitle: "Retrieve method",
|
||||
// New: cached ID utils
|
||||
saveId_dis: "Save ID",
|
||||
useCachedId_dis: "Use cached ID",
|
||||
saveId_tips: "Save current ID for quick reuse later",
|
||||
useCachedId_tips:
|
||||
"Quickly use the previously saved ID to avoid typing",
|
||||
},
|
||||
// New: cache messages
|
||||
saveId_success: "Saved to cache",
|
||||
},
|
||||
home: {
|
||||
h1: "Free Secure Online Clipboard & File Transfer Tool",
|
||||
|
||||
@@ -331,7 +331,15 @@ export const es: Messages = {
|
||||
readClipboard_dis: "Pegar ID de Sala",
|
||||
retrieveRoomId_placeholder: "Ingresa ID de Sala",
|
||||
RetrieveMethodTitle: "Método de recuperación",
|
||||
// New: cached ID utils
|
||||
saveId_dis: "Guardar ID",
|
||||
useCachedId_dis: "Usar ID en caché",
|
||||
saveId_tips: "Guarda el ID actual para reutilizarlo rápidamente",
|
||||
useCachedId_tips:
|
||||
"Usa el ID guardado previamente para evitar escribir",
|
||||
},
|
||||
// New: cache messages
|
||||
saveId_success: "Guardado en caché",
|
||||
},
|
||||
home: {
|
||||
h1: "Herramienta Gratuita de Portapapeles y Transferencia de Archivos en Línea Segura",
|
||||
|
||||
@@ -338,7 +338,16 @@ export const fr: Messages = {
|
||||
readClipboard_dis: "Coller l'ID de salle",
|
||||
retrieveRoomId_placeholder: "Entrez l'ID de salle",
|
||||
RetrieveMethodTitle: "Méthode de récupération",
|
||||
// New: cached ID utils
|
||||
saveId_dis: "Enregistrer l’ID",
|
||||
useCachedId_dis: "Utiliser l’ID en cache",
|
||||
saveId_tips:
|
||||
"Enregistrez l’ID actuel pour une réutilisation rapide",
|
||||
useCachedId_tips:
|
||||
"Utilisez l’ID précédemment enregistré pour éviter la saisie",
|
||||
},
|
||||
// New: cache messages
|
||||
saveId_success: "Enregistré dans le cache",
|
||||
},
|
||||
home: {
|
||||
h1: "Outil gratuit de transfert de fichiers et de presse-papiers en ligne sécurisé",
|
||||
|
||||
@@ -323,7 +323,14 @@ export const ja: Messages = {
|
||||
readClipboard_dis: "ルームIDを貼り付け",
|
||||
retrieveRoomId_placeholder: "ルームIDを入力",
|
||||
RetrieveMethodTitle: "取得方法",
|
||||
// New: cached ID utils
|
||||
saveId_dis: "ID を保存",
|
||||
useCachedId_dis: "保存済みIDを使用",
|
||||
saveId_tips: "現在のIDを保存して次回すぐに使えるようにします",
|
||||
useCachedId_tips: "以前に保存したIDを使って入力を省略できます",
|
||||
},
|
||||
// New: cache messages
|
||||
saveId_success: "キャッシュに保存しました",
|
||||
},
|
||||
home: {
|
||||
h1: "無料で安全なオンラインクリップボード&ファイル転送ツール",
|
||||
|
||||
@@ -321,7 +321,16 @@ export const ko: Messages = {
|
||||
readClipboard_dis: "방 ID 붙여넣기",
|
||||
retrieveRoomId_placeholder: "방 ID 입력",
|
||||
RetrieveMethodTitle: "검색 방법",
|
||||
// New: cached ID utils
|
||||
saveId_dis: "ID 저장",
|
||||
useCachedId_dis: "저장된 ID 사용",
|
||||
saveId_tips:
|
||||
"현재 ID를 저장하여 다음에 빠르게 사용할 수 있어요",
|
||||
useCachedId_tips:
|
||||
"이전에 저장한 ID를 사용하여 입력을 줄입니다",
|
||||
},
|
||||
// New: cache messages
|
||||
saveId_success: "캐시에 저장되었습니다",
|
||||
},
|
||||
home: {
|
||||
h1: "무료 보안 온라인 클립보드 및 파일 전송 도구",
|
||||
|
||||
@@ -283,7 +283,8 @@ export const zh: Messages = {
|
||||
noFilesForFolderMsg: "在文件夹 '{folderName}' 中未找到文件。",
|
||||
zipError: "创建 ZIP 文件时出错。",
|
||||
fileNotFoundMsg: "未找到要下载的文件 '{fileName}'。",
|
||||
confirmLeaveWhileTransferring: "传输将中断,已设置保存目录时可续传。确定退出?",
|
||||
confirmLeaveWhileTransferring:
|
||||
"传输将中断,已设置保存目录时可续传。确定退出?",
|
||||
leaveWhileTransferringSuccess: "已退出房间,传输已中断",
|
||||
html: {
|
||||
senderTab: "发送",
|
||||
@@ -296,7 +297,7 @@ export const zh: Messages = {
|
||||
inputRoomIdprompt: "您的房间ID(可编辑):",
|
||||
joinRoomBtn: "加入房间",
|
||||
generateSimpleId_tips: "简单ID",
|
||||
generateRandomId_tips: "随机ID",
|
||||
generateRandomId_tips: "随机ID",
|
||||
readClipboardToRoomId: "粘贴房间ID",
|
||||
enterRoomID_placeholder: "输入房间ID",
|
||||
retrieveMethod: "接收方式",
|
||||
@@ -307,7 +308,14 @@ export const zh: Messages = {
|
||||
readClipboard_dis: "粘贴房间ID",
|
||||
retrieveRoomId_placeholder: "输入房间ID",
|
||||
RetrieveMethodTitle: "接收方式",
|
||||
// New: cached ID utils
|
||||
saveId_dis: "保存ID",
|
||||
useCachedId_dis: "使用缓存ID",
|
||||
saveId_tips: "保存ID后,下次可以快捷使用该ID",
|
||||
useCachedId_tips: "可以快捷使用之前保存的ID,避免手动输入",
|
||||
},
|
||||
// New: cache messages
|
||||
saveId_success: "缓存成功",
|
||||
},
|
||||
home: {
|
||||
h1: "免费安全的在线剪贴板与文件传输工具",
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// Utilities to cache a single room ID in browser localStorage
|
||||
// Works on client only; no-ops on server.
|
||||
|
||||
const CACHED_KEY = "pd_cached_room_id_v1";
|
||||
|
||||
function isClient() {
|
||||
return typeof window !== "undefined";
|
||||
}
|
||||
|
||||
export function getCachedId(): string | null {
|
||||
if (!isClient()) return null;
|
||||
try {
|
||||
const v = window.localStorage.getItem(CACHED_KEY);
|
||||
return v && v.trim() ? v : null;
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function setCachedId(id: string): void {
|
||||
if (!isClient()) return;
|
||||
try {
|
||||
window.localStorage.setItem(CACHED_KEY, id);
|
||||
} catch (_) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
export function clearCachedId(): void {
|
||||
if (!isClient()) return;
|
||||
try {
|
||||
window.localStorage.removeItem(CACHED_KEY);
|
||||
} catch (_) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,6 +254,11 @@ export type ClipboardAppHtml = {
|
||||
readClipboard_dis: string;
|
||||
retrieveRoomId_placeholder: string;
|
||||
RetrieveMethodTitle: string;
|
||||
// New: cached ID utilities
|
||||
saveId_dis: string;
|
||||
useCachedId_dis: string;
|
||||
saveId_tips: string;
|
||||
useCachedId_tips: string;
|
||||
};
|
||||
|
||||
export type ClipboardApp = {
|
||||
@@ -274,6 +279,8 @@ export type ClipboardApp = {
|
||||
fileNotFoundMsg?: string;
|
||||
confirmLeaveWhileTransferring: string;
|
||||
leaveWhileTransferringSuccess: string;
|
||||
// New: cache messages
|
||||
saveId_success: string;
|
||||
};
|
||||
|
||||
export type Home = {
|
||||
|
||||
Reference in New Issue
Block a user